Компьютерная математика Weekly – Telegram
Компьютерная математика Weekly
1.06K subscribers
48 photos
2 videos
70 links
Download Telegram
геометрия пи в экселе

выше обсуждались разные способы вычисления π, в т.ч. 1-1/3+1/5-1/7+… = π/4 ( https://news.1rj.ru/str/compmathweekly/42 )

а можно ли как-то несложно поставить компьютерный эксперимент, где π возникает сразу «геометрически», без анализа?

π — это площадь круга радиуса 1, поэтому среди точек квадрата 0⩽X,Y⩽1 доля точек, попадающих в (четвертинку) круга радиуса 1 с центром в начале координат, равна π/4

теперь можно вычислять π геометрически хоть в экселе — по методу Монте-Карло: берем 100500 строк, в каждой пишем по паре случайных чисел X и Y, считаем в скольких строках X²+Y²⩽1, полученную долю умножаем на 4

конечно, способ не особо эффективный — для 1000 строк получается приближение уровня π≈3,1

приятно, когда читая лекцию или проводя занятие и сам узнаешь что-то… рассказывал сегодня учителям в Т-Образовании про компьютерную математику, а коллега на такой способ обратил внимание

P.S.
сумма из начала поста на самом деле получается, если думать про те же площади — но брать не случайные точки, а все точки достаточно мелкой сетки… про это есть отличный ролик 3Blue1Brown, если кто не видел, https://youtu.be/NaL_Cb42WyY
👍7👌2🔥1
6.
попробуем еще чуть-чуть продвинуться в подсчетах кривых

в прошлый раз ( https://news.1rj.ru/str/compmathweekly/72 ) посчитали количество прямых на гиперповерхности степени 5 в P^4

теперь попробуем посчитать на ней же коники

парадигма та же: объекты с нужными свойствами представляем как нули сечения подходящего расслоения на пространстве всевозможных объектов (это обобщение плана «задаем уравнениями»), тогда количество получается как интеграл класса Черна этого расслоения, и может быть найдено либо при помощи вычислений в кольце когомологий, либо при помощи формулы локализации (а тонкие вопросы трансверсальности сечения, невырожденности решений и т.п. — цинично заметаем под ковер)

каждая коника в P^4 лежит в какой-то плоскости и высекается там квадратным уравнением... то есть пространство C всех коник — это P(Sym^2 E), где E — двойственное¹ тавтологическому трехмерное расслоение на Gr(3,5)=PGr(2,4)

¹ прошу прощения за смену обозначений, но надоело таскать кучу звездочек

уравнение f нашей квинтики задает сечение расслоения Sym^5 E, а условие «данная коника лежит на квинтике» значит, что f [в ограничении на плоскость коники] = (уравнение коники)⋅(что-то кубическое) — т.е. нас интересуют точки, для которых сечение попадает в подрасслоение (Sym^3 E)⊗O(-1) — другими словами, нас интересует старший класс Черна фактора F := Sym^5 E / (Sym^3 E)(-1)

(проверка: dim C=11, т.к. оно расслаивается над 6-мерным грассманианом с 5-мерным слоем; dim F=7⋅6/2-5⋅4/2=11 — размерности сходятся)

осталось реализовать компьютерное вычисление интеграла c_11(F) по C

(
прямолинейно-алгебраическое вычисление вот какое:

пусть x0, x1, x2 — корни Черна E, тогда у Sym^n E корни Черна — это i⋅x0+j⋅x1+k⋅x2 | i+j+k=n

H(C) = H(Gr)[t] / prod(t-x), где t — класс Черна O(1), а произведение берется по корням Ч. для Sym^2 E

нам нужно взять произведение 1+x по корням Ч. для Sym^5 E, разделить на произведение 1+x-t по корням Ч. для Sym^3 E, разложить t в степени 6 и выше по соотношению выше, найти коэффициент при s[2,2,2]⋅t^5

вроде как раз задача для компутера — руками это убьешься считать — но пока не закодил… надеюсь, дальше либо справлюсь, либо посчитаю все-таки по локализации
)
5🤔1
слушал мини-курс Батырева про дискриминант, где рассказывалось в т.ч. про такое

как выглядит дискриминант многочлена a_0+a_1x+…+a_nx^n?

уже для n=4 ответ sage выглядит несколько устрашающе:


n = 4

R = PolynomialRing(QQ, 'a', n+1)
a = R.gens()
S.<x> = PolynomialRing(R)
f = sum(a[i]*x^i for i in range(n+1))
D = f.discriminant()

print(D)



a1^2*a2^2*a3^2 - 4*a0*a2^3*a3^2 - 4*a1^3*a3^3 + 18*a0*a1*a2*a3^3 - 27*a0^2*a3^4 - 4*a1^2*a2^3*a4 + 16*a0*a2^4*a4 + 18*a1^3*a2*a3*a4 - 80*a0*a1*a2^2*a3*a4 - 6*a0*a1^2*a3^2*a4 + 144*a0^2*a2*a3^2*a4 - 27*a1^4*a4^2 + 144*a0*a1^2*a2*a4^2 - 128*a0^2*a2^2*a4^2 - 192*a0^2*a1*a3*a4^2 + 256*a0^3*a4^3


но кое-что интересное можно увидеть, если этот многочлен нарисовать — а точнее нарисовать его многогранник Ньютона (для каждого входящего в дискриминант монома П a_i^{k_i} отмечаем точку с координатами (…,k_i,…) и берем выпуклую оболочку)

буквально как написано уже для n=4 будет что-то в 5-мерном пространстве, но это иллюзия: ∑ k_i = const и ∑ i k_i = const, то есть реально всё лежит в обычном 3-мерном пространстве


support = [m.exponents()[0] for m in D.monomials()]

M = matrix(QQ, n+1, n-1)
for i in range(n-1):
M[i,i], M[i+1,i], M[i+2,i] = 1, -2 ,1
def exponent_map(x):
v = vector(x) - vector([0]+[2]*(n - 1)+[0])
return tuple(M.solve_right(v))

projected_support_b = [exponent_map(x) for x in support]
poly_b = Polyhedron(vertices=projected_support_b)
poly_b.plot()


вот на картинке видно, что получается такой кубоид — и для любой степени, говорят, получается кубоид (соответствующей размерности)

на этом история не заканчивается — n! копий такого кубоида складываются в пермутаэдр; если брать сумму мономов, попавшие в одну грань кубоида, то получившийся многочлен хорошо раскладывается на множители… хотел бы это всё компьютерно увидеть

конспект первой лекции есть по ссылке mccme.ru/dubna/2025/notes/batyrev-notes.pdf
🔥103
если уж зашла речь про дискриминант — два слова про то, как его нарисовать

любое уравнение степени 4 нетрудно привести к виду x^4+px^2+qx+r=0

у каких из уравнений такого вида есть кратные корни?

можно посчитать в sage (или даже на бумажке) дискриминант такого уравнения… тут слагаемых поменьше, но всё равно выглядит страшновато:
-4*p^3*q^2 + 16*p^4*r - 27*q^4 + 144*p*q^2*r - 128*p^2*r^2 + 256*r^3


если в лоб спросить ту же геогебру нарисовать, где в трехмерном пространстве такое выражение обращается в 0, то ничего не получится — лучше действовать не настолько в лоб

можно начать с совсем вырожденных уравнений — у которых есть корень кратности 3: если коэффициент при x^3 нулевой, то сумма всех корней 0, то есть корни должны быть (t,t,t,-3t), а значит, (p,q,r)=(-6t^2,8t^3,-3t^4) — такую кривую нарисовать несложно

а произвольное уравнение с кратным корнем t (и нулевым коэффициентом при x^3) можно записать в виде (x-t)²(x²+2tx+s)

ну уже не раскрывая скобки видно, что выражения для (p,q,r) будут линейными по s, правда? то есть наша поверхность линейчатая (состоит из прямых — а именно, как можно понять, из касательных к описанной выше кривой!)

а если скобки все-таки раскрыть, то с получающимся параметрическим заданием поверхности справится любая геогебра — получается замечательная поверхность “ласточкин хвост”, вот можно на это посмотреть: www.geogebra.org/m/ftjewyex

больше разговоров и много красивых картинок есть на сайте Математических этюдов: etudes.ru/etudes/swallow-tail/
👍7🔥41
возьмем какой-нибудь многочлен (от одной переменной с натуральными коэффициентами) и возведем в большую степень

ну будет непонятное море мономов с большими коэффициентами… но тут уже обсужалось, что полезно сделать в таком случае: построить график

что мы увидим? почему?

под спойлером скрыт пример картинки (конкретно — list_plot(((2+7*x+x^4+5*x^5)^57).coefficients(),plotjoined=True) в sage)

(такой иллюстрацией ЦПТ поделился Александр Ч. в комментариях у «Кроссворда Тьюринга»)
🔥43
в предыдущем посте обсуждалось, что будет, если возвести в большую степень многочлен с неотрицательными коэффициентами

а вот картинка для list_plot(((1+3*x-x^2+x^3)^100).coefficients(),plotjoined=True)

почему «горбов» в данном случае два (рядом с x=N и x=2N, с одинаковым порядком величины)? что будет происходить для произвольного многочлена? другими словами, какой аналог ЦПТ для ситуации, когда разрешены не только неотрицательные (а произвольные… пускай даже комплексные) вероятности?

(думал, разберусь и напишу… это не сложилось, но мб кто-то в комментариях объяснит — upd: indeed, см. комментарии)
👍41
треугольник Серпинского как график функции

Никита Медведь рассказал забавное

рассмотрим для k-битовых чисел функцию, переводящее N в N&Nrev, и нарисуем её график — оказывается, он выглядит как треугольник Серпинского

читателям предлагается этот эффект объяснить

===

Nrev — строка из нулей и единиц, прочитанная в обратном порядке, & — побитовое И

источник: https://www.reddit.com/r/askmath/comments/1mvxrjn/if_you_reverse_the_bits_of_a_number_n_and_then/

для желающих развлекаться — код оставлю в комментариях
10🤯6🔥3
чему равен НОД(n^5+5,(n+1)^5+5)? первое впечатление, возможно, что это глупый вопрос типа того, чему равен НОД(n,n+1)… и действительно, для небольших n легко проверить, что всё время получается единица, но ———

желающим предлагается разобраться

в комментарии положу эксель-табличку для экспериментов (на скрытой под спойлером картинке — что она дает для НОД(n^3+3,(n+1)^3+3) при n=1..150), но буквально для исходной задачи в экселе ничего кроме единиц не увидишь
👍12🔥4
( комментарий к https://news.1rj.ru/str/compmathweekly/84 )

пусть НОД(f(n),g(n))>1 — и, соответственно, делится на какое-то простое p

это значит, что по модулю p у многочленов f и g есть общий корень (а именно, n), то есть Res(f,g) = 0 mod p

в данном случае результант равен¹ простому числу p=1968751, поэтому если НОД не 1, то он равен этому числу (и это уже намекает, что пример вряд ли найдется среди небольших n… а, скажем, для n^17+9 и (n+1)^17+9 получается простое число порядка 10^50)

остается найти² корни пятой степени из -5 по этому модулю (96502, 533360, 533361, 1066696, 1707583) и поискать среди них³ отличающиеся на 1

окончательно получаем, что НОД равен 1968751 для n=533360+1968751m (и 1 иначе)


(можно обойтись и без слова 'результант': шагами a la алгоритм Евклида (f,g)→(af+bg,f) нетрудно получить, что в идеале (f,g) лежит число (паразитический множитель)×1968751 — см. код в комментариях — и плясать от этого)

в комментариях М.Алексеев поделился еще ссылкой arxiv.org/abs/1608.07936 (опубликовано в AMM) — там объясняется, что если результант свободен от квадратов, то все его делители возникают как значения НОДа

¹ если хочется посчитать это в sage, то синтаксис не совсем очевидный: f.resultant(g,x)

² R.<x> = PolynomialRing(GF(1968751)); (x^5-5).factor()

³ что такие найдутся — понятно, кстати, заранее: p=5k+1, поэтому если хотя бы один корень лежит в поле, то лежат и остальные (и из обращения в 0 результанта какие-то два отличаются на 1); а если x и x+1 — корни в расширении, то из Галуа-инвариантности прибавлять единицу можно к любому корню и сразу противоречие
👍4🔥3
склеим стороны 2n-угольника попарно 'с сохранением ориентации' (без перекрутки) — какие поверхности могут при этом получиться?

если у квадрата склеивать соседние стороны, то (топологически) получится сфера, если противоположные — тор

если не думали никогда, как склеить подобным образом 'сферу с 2 ручками' (крендель), то полезно, конечно, задуматься



но еще можно задать вопрос про количества: сколькими способами можно склеить из 2n-угольника сферу с g ручками?

для g=0 после склейки граница превратится в плоское дерево (и наоброт, если обойти вокруг дерева, то можно увидеть границу многоугольника, приклееную к этому дерево — по две стороны у каждого ребра)

то есть в роде 0 получаются милые многим числа Каталана — а интересно, что происходит дальше

тут повод сделать паузу и задуматься, как же по склейке понять, какая поверхность получается (требуется рецепт, достаточно конкретный, чтобы даже питон понял)



в следующий раз напишу, думаю, как это перебрать на компутере (ну… для небольших n — всего склеек (2n-1)!!, так что особо далеко так не уйдешь)

давно уже хотел это сделать, а тут нашелся повод
6👍1
пусть мы как-то склеили стороны многоугольники (попарно, с сохранением ориентации) — как понять, что за поверхность получается?

самый простой способ (по крайней мере, для лишенного геометрического воображения компьютера) — посчитать Эйлерову характеристику: с одной стороны, она равна 2-2g, а с другой стороны, из 2n-угольника получается карта с 1 гранью, n ребрами и… надо только как-то посчитать количество вершин

если считать, что i-е ребро соединяет вершины i и i+1, то при его склейке с j-м ребром i-я вершина склеевается с (j+1)-й… то есть если думать про склейку как про перестановку (инволюцию на множестве сторон), то количество вершин — это количество циклов в композиции этой перестановки с циклическим сдвигом на 1

вообще книжка Звонкина и Ландо учит, что про ленточный (вложенный в поверхность) граф бывает удобно думать как про тройку перестановок… но я отвлекся, а пора переходить к реализации


перебор инволюций реализовал в том же духе, как перебирал в https://news.1rj.ru/str/compmathweekly/9 разбиения на доминошки:

def involutions(n,state=[]):
if state == []:
state = [-1]*(2*n)
for i in range(2*n):
if state[i] == -1:
for j in range(i+1,2*n):
if state[j] == -1:
newst = state.copy()
newst[i], newst[j] = j, i
yield from involutions(n,newst)
return
yield state

осталось добавить вычисление рода через подсчет количества циклов:

def genus(perm):
N = len(perm)
state = [(perm[i]+1) % N for i in range(N)]
v = 0
for i in range(N):
j = state[i]
if j != -1:
v += 1
while j != i:
state[j], j = -1, state[j]
return (N//2-v+1)//2
# v-n+1 = 2-2g => g = (n-v+1)/2

for n in range(1,6+1):
counts = [0]*(n//2+1)
for perm in involutions(n):
counts[genus(perm)] += 1
print(f"n={n}:",*counts)



n=1: 1
n=2: 2 1
n=3: 5 10
n=4: 14 70 21
n=5: 42 420 483
n=6: 132 2310 6468 1485




в следующий раз попробую мб написать, что можно увидеть в таблице возникающих чисел
5
Forwarded from Такие себе мысли
Intermission

Разгребал недавно завал на гугл-диске, нашел прикольное. Рубрика "эксперименты, упаси господи", релевантное message passingу в графовых нейронках.

Гугл-таблицы - идеальный инструмент для демонстрации дискретной диффузии с граничными условиями типа Дирихле.

0. Разрешаем в настройках таблицы циклические вычисления, выкручиваем число итераций на дофига, точность на эпсилон.
1. Рисуем из клеточек область.
2. На границе ставим вещественные чиселки.
3. Во внутренних клетках области ставим везде формулу =среднее арифметическое четырех соседей (легко задать в одной клетке и автоматически скопипастить).
4. Чтобы было красиво, делаем внутри области conditional formatting с градиентной расцветкой.

Наслаждаемся распределением тепла без регистрации и СМС. К сожалению, вещественные векторы в ячейки гугл-таблицы поставить не удается - а то можно было бы запускать нейронки прямо в гугл-таблицах.

Можете вот скопировать, там еще на прогрев тора можно позалипать

Но что если заполнять таблицу каким-нибудь более интересным типом данных? Если в качестве типа данных выбрать фиксированную решетку, то получится наука про лапласиан Тарского. А если категорию, обогащенную над кванталями (свят-свят-свят), то будет лапласиан Ловера.

Зачем? Потому что можем. А еще потому что прикольно какие-то простенькие куски MLя перенести из вещественной вселенной во что-то более дискретно-категорное. В отличие от клеточных автоматов, это работает не только на дискретной плоскости, но и над произвольными графами или даже клеточными комплексами.

Единственная категория, обогащенная над кванталями, которую я нашел в гугл-таблицах - это Bool, в качестве пулинга - дизъюнкция соседей. Жизнь Конвея и другие клеточные автоматы тоже можно сделать, правда, получится с ошибками.

Такое дискретное, правда, в табличке плохо работает: вся итерация останавливается, когда значение в одной клетке за один шаг не поменялось, а такое с булевыми значениями редко происходит. Поскольку гугл при вычислении просто пересчитывает ячейки сверху вниз слева направо, то процесс дискретной диффузии тормозится за одну эпоху: значения апдейтятся последовательно и получается что-то на первый взгляд странное (хотя и объяснимое если подумать). Можно в качестве шага диффузии копипастить значение какой-нибудь граничной клетки в саму себя - это вынуждает табличку пересчитать то, что имеет смысл пересчитать, прогнав еще одну эпоху.
7😱5😁2
Компьютерная математика Weekly
треугольник Серпинского как график функции Никита Медведь рассказал забавное рассмотрим для k-битовых чисел функцию, переводящее N в N&Nrev, и нарисуем её график — оказывается, он выглядит как треугольник Серпинского читателям предлагается этот эффект объяснить…
знаете ли вы, как выглядит график синуса?

если да, то подумайте, какую картинку должен выдать код ниже… а потом посмотрите под спойлером на реальный результат


import numpy as np
import matplotlib.pyplot as plt

x = np.arange(-10, 10, 0.001)
y = np.sin(314*x)

plt.plot(x,y, marker='.', linestyle='none')
plt.show()


// из статьи П.Панова «Как выглядит график синуса?» в Кванте №3 за 2020 год (via С.Дориченко); см. также статью Е.Бакаева «Еще раз о графике синуса» в №4
🔥10😱4🤔31
еще немного повозимся с тождествами — следующая серия начинается с того, что

(a+b)²/(a-c)(b-c)+(b+c)²/(b-a)(c-a)+(c+a)²/(c-b)(a-b) = 1

дальше

(a+b)⁴/(a-c)(b-c)(a-d)(b-d) + … = 2

а дальше количество слагаемых быстро (квадратично) растет, но по крайней мере первые суммы легко посчитать на компьютере:

def sum2(n):
m = 2*n-2
R = PolynomialRing(QQ, 'x', n+1)
x = R.gens()
return sum(
(x[i]+x[j])^m / prod((x[i]-x[k])*(x[j]-x[k])
for k in range(n+1) if k != i and k != j)
for j in range(n+1) for i in range(j)
)

for n in range(2,6+1): print(n,sum2(n))


понятно ли, что за последовательность возникает? можете ли это доказать?

(бонус для любителей геометрии: на самом деле, sum2(2) считает количество прямых через 2 точки на плоскости, sum2(3) — через 4 прямые общего в положения в пространстве… и так далее)

а как эти тождества обобщить (скажем, в прошлой серии тождеств вместо монома в числителе можно было написать любой многочлен подходящей степени)?
👍2🔥1
как проверить формулу на картинке?

самая понятная формула, выражающая объем тетраэдра через его ребра, дается определителем Кэли–Менгера:

CM = matrix([
[0, 1, 1, 1, 1],
[1, 0, U**2, V**2, w**2],
[1, U**2, 0, W**2, v**2],
[1, V**2, W**2, 0, u**2],
[1, w**2, v**2, u**2, 0 ]
])
V2_CM = det(CM)/288


для полиномиальности здесь сразу вычисляется не объем, а его квадрат… но формуле от Маркелова и этого недостаточно, так как в определение «переменных третьего поколения» (a, b, c, d) через «переменные второго поколения» входят квадратные корни

но если раскрыть скобки в числителе, то останутся только квадраты этих товарищей, а также произведение abcd (которое тоже полином от «переменных второго поколения»)


X, x = (w-U+v)*(U+v+w), (U-v+w)*(v-w+U)
Y, y = (u-V+w)*(V+w+u), (V-w+u)*(w-u+V)
Z, z = (v-W+u)*(W+u+v), (W-u+v)*(u-v+W)

a2 = x*Y*Z
b2 = y*Z*X
c2 = z*X*Y
d2 = x*y*z
abcd = X*Y*Z*x*y*z

num2 = (
2*(a2*b2+a2*c2+a2*d2+b2*c2+b2*d2+c2*d2)
- (a2**2+b2**2+c2**2+d2**2)
+ 8*abcd
)
V2_markelov = num2/(192*u*v*w)**2


после этих ухищрений V2_CM - V2_markelov.expand() действительно дает ноль



но вопрос, что всё это значит — можно ли выражениям типа b+c+d-a придать какой-то геометрический смысл, скажем, как это происходит в формуле Герона — остается

мб кто-то в комментариях научит
👍7🔥3
контекст для предыдущего — такого рода как выше объяснение (неполное, текст на картинке взят из книги Блинкова «Учимся на чужих ошибках») формулы Герона

вообще теорема Гильберта о нулях говорит, что многочлен с точностью до умножения на константу определяется своими нулями… правда (не обсуждая даже, почему для какой-то степени S есть полиномиальная формула) тут желательно рассматривать многочлен для всевозможных значений переменных, причем комплексных

например, в формуле для площади нет сомножителя abc — разве площадь не обращается в ноль, когда одна из сторон становится нулевой? а вот, у прямоугольного треугольника с катетами 1 и i площадь ненулевая, но гипотенуза имеет нулевую длину

что хуже, длина отрезка в этом комплексном мире вообще не определена (чему равна длина отрезка от -i/2 до +i/2: +i или -i?), определен только ее квадрат (то же можно сказать и про саму площадь, кстати)

похожая вещь происходит с формулой для объема тетраэдра — казалось бы, если для площадей граней тетраэдра выполняется равенство S1=S2+S3+S4, то он вырождается, так что формула для объема должна раскладываться на кучу множителей… а в реальности определитель Кэли-Менгера представляет собой неприводимый многочлен!

но всё-таки чего-то в духе рассуждения на картинке для объема тетраэдра хотелось бы… и в этом смысле формула им. Маркелова привлекает наличием факторизации
👍11
вот таблица ответов (количества склеек многоугольника в поверхности разного рода) от программы выше — что можно в ней увидеть?

в такой “нумерологии” нередко помогает обращать внимание на делимости

вот например если посмотреть на первую колонку, то бросается в глаза, что 14 и 42 делятся на 7, 132 и 429 на 11… раз у соседних чисел есть большой общий делитель, можно попробоват посмотреть на их частные

получаем 1, 2, 2 1/2, 2 4/5, 3, 3 1/7, 3 1/4, 3 1/3, 3 2/5, 3 5/11, 3 1/2… — видно, что числа не очень далеки от целых, а именно становятся целыми при умножении на n+1 (тут тоже особенно помогает обратить внимания на числа типа 7, 11)

если на n+1 домножить, то получится… ну сами попробуйте — мб со школьниками — после этого легко придумать гипотезу про формулу

конечно, про числа Каталана и так многие знают, но абсолютно тот же трюк можно проделать со второй колонкой…

а можно посмотреть по-другому: когда в колонках рядом стоят числа 5 и 10, 14 и 70, 42 и 420, 132 и 2310, то естественно попробовать одно на другое поделить — и если это сделать (и еще умножить на 2 для целочисленности), получается 1, 4, 10, 20, 35, 56… (думаю, и без спойлера понятно, что это ; )


но можно посмотреть и куда-то еще… вот, скажем, на верхние числа в колонках… тут даже без компьютера бросается в глаза число 225225

1001 = 7.11.13, а значит, 225225 = 15².1001 = 3.5.7.11.13.15 недалеко ушло от двойного факториала… как и, например, 21… в общем, тоже закономерность нетрудно распознать


если замечаете в такой таблице что-то еще — пишите
1👍1🤔1
вчера на уроке хотел быстренько показать как выглядят слагаемые в det(AB) по сравнению с det(A)det(B)

но не смог заставить sage раскрыть скобки не сокращая одинаковые члены

в качестве работы над ошибками написал сегодня это на коленке просто в питоне — получилось так:


from itertools import permutations
from functools import reduce

def sgn(perm):
inv = sum(perm[i] > perm[j] for i in range(len(perm)) for j in range(i+1, len(perm)))
return -1 if inv % 2 else 1

def mult_terms(A, B):
for As, Ams in A:
for Bs, Bms in B:
yield (As*Bs,Ams+Bms)

def mtrx(label, n):
return [ [ [ (1, [f"{label}{i+1}{j+1}"]) ] for j in range(n) ] for i in range(n) ]

def mtrxAB(l1,l2, n):
return [ [ [ (1, [f"{l1}{i+1}{s+1}", f"{l2}{s+1}{j+1}"]) for s in range(n) ] for j in range(n) ] for i in range(n) ]

def det_terms(mtrx):
n = len(mtrx)
for sigma in permutations(range(n)):
for inner_sign, factors in reduce(mult_terms, [ mtrx[i][sigma[i]] for i in range(n) ]):
yield (sgn(sigma)*inner_sign, factors)

def print_terms(terms):
for s, ms in terms:
print(f"{'+' if s>0 else '-'} {'.'.join(sorted(ms))}")

N = 3
detA = list(det_terms(mtrx("a", N)))
detB = list(det_terms(mtrx("b", N)))
print_terms(mult_terms(detA, detB))
print("---")
print_terms(det_terms(mtrxAB("a","b", N)))


можно запустить — и посмотреть, что как с чем сокращается

***

понравилось, что вот все эти определения «многочлен — это формальная сумма мономов…» и т.п. здесь реально работают
4
предыдущий код можно обернуть в классы для мономов и полиномов, начиная с чего-нибудь в духе

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²>
🔥2🤯21
смотрел видео ниже

кто учит школьников алгебре — могут оценить, что всплывают родные всем темы преобразований графиков функций (в т.ч. с модулями), поворотов в координатах и т.п. — а при этом в результате получается что-то прикольное

попробовать сделать что-то своё можно на twigl.app (например)
Записал настоящий обучающий видос, с музыкой, скринкастом и объясняющими демками.

Ютуб youtu.be/zblepnHHCSA
ВК vkvideo.ru/video-230304511_456239017
🔥3👍1