Эксперимент 002: решение задач по планиметрии с помощью модуля "Planimetrics Calculus" библиотеки Kone
(Проект эксперимента доступен здесь.)
Задачи по планиметрии развились как отдельное интересное направление головоломок. Некоторые находят изысканные решения сложных задач, понятные всякому, кто помнит школьную геометрию. Некоторые развивают такие мощные инструменты как вычисления в комплексных числах и проективные движения, чтобы быстрее решать трудные задачи и иногда обобщать их. Некоторые тренируют компьютерные программы, которые могут решать задачи по геометрии или придумывать новые.
В библиотеке Kone есть модуль "Planimetrics Calculus", который позволяет исследовать задачи, описываемые определённым образом, с точки зрения многочленов в проективном пространстве. Этот эксперимент служит списком примеров и испытательным полигонов этого модуля.
Но сначала короткое теоретическое введение: о чём речь?
Пусть нам дано векторное пространство над полем . Рассмотрим отношение эквивалентности на , что тогда и только тогда, когда есть , что . Тогда фактор-множество называется проективизацией и просто проективным пространством и обозначается .
Если выбрать в любой базис, то можно ввести координаты. Правда, отождествляет точки с пропорциональными координатами. Т.е. . Тогда можно отождествить такие наборы координат с точностью до пропорциональности. Такие "координаты" всякой точки проективного пространства называются однородными координатами этой точки и обозначаются . Аналогично можно ввести однородные координаты гиперпространства.
Давайте заметим, что прямая проходящая через точки и имеет вид
Т.е. выражается как три однородных многочлен второй степени от , , и , , . А если мы вложим обычную плоскость в проективную отображением , то такими же многочленами можно выразить середину отрезка меж этих точек, серединный перпендикуляр и даже центр окружности, проходящей через три данные точки. При этом и условия коллинеарности точек, конкурентности прямых и другие тоже описываются многочленами. Т.е. если нам даны какие-то случайные объекты (точки и прямые), мы на них построили таким образом новые объекты и про какие-то объекты что-нибудь спросим, то это условие получится многочленами от координат изначальных объектов. А значит верным всегда тогда и только тогда, когда многочлен нулевой.
Таким образом мы покажем, как на основе этого модуля-фреймворка проверять верность теорем из планиметрии.
Время экспериментов!
Каждый эксперимент начнётся с шаблона
fun main(): Unit = koneContextRegistry.inPlanimetricsCalculationSpaceScopeFor(rationalType) {
...
}
Не бойтесь, это всего лишь настройка окружения для нашей задачи.
Сюжет: прямая Эйлера
(Файл eulerLine.kt.)
Возьмём случайный треугольник :
val A by Point
val B by Point
val C by Point
И возьмём вв нём центроид , ортоцентр и центр описанный окружности .
val M = centroid(A, B, C)
val H = orthocenter(A, B, C)
val O = circumcenter(A, B, C)
Просто проверим, что они лежат на одной прямой.
println(collinearityTest(M, H, O))
Эта строка возвращает true, т.е. они реально лежат на одной прямой!
И эта прямая называется прямой Эйлера.
В библиотеке есть функция для вычисления и прямой Эйлера.
val l = eulerLine(A, B, C)
Можно проверить, что это реально прямая Эйлера, проверив лежат ли на ней , и .
for (P in listOf(M, H, O)) println(P isLyingOn l)
Выведется трижды true.
Также можно провести прямую через, например, и и проверить на совпадение с полученной прямой:
println(l equalsTo lineThrough(O, H))
Сюжет: теорема Дезарга
(Файл desarguesTheorem.kt.)
В этом сюжете мы попытаемся доказать прямую и обратную теоремы Дезарга за один раз.
В задаче фигурируют два треугольника случайного расположения. Давайте определим их по их вершинам:
val A1 by Point
val B1 by Point
val C1 by Point
val A2 by Point
val B2 by Point
val C2 by Point
Под капотом декларация
val P by Point
заводит переменные P_x, P_y и P_z, превращает их в многочлены (т.е. многочлен и т.д.)
и создаёт объект точки, однородные координаты которой — три полученных многочлена.
Теперь проведём вычислим прямые , и :
val a = lineThrough(A1, A2)
val b = lineThrough(B1, B2)
val c = lineThrough(C1, C2)
Под капотом lineThrough просто берёт многочлены-координаты двух полученных точек и вычисляет от них выражение из теоретического введения.
Теперь вычислим точки пересечения пар прямых , и :
val Aprime = intersectionOf(lineThrough(B1, C1), lineThrough(B2, C2))
val Bprime = intersectionOf(lineThrough(C1, A1), lineThrough(C2, A2))
val Cprime = intersectionOf(lineThrough(A1, B1), lineThrough(A2, B2))
Вспомним, что теорема Дезарга говорит, что , и конкурентны тогда и только тогда, когда , и коллинеарны. Давайте докажем это. Но сделаем следующий неожиданный ход. Вычислим такие условия:
- условие конкурентности , и , умноженное на условие коллинеарности , и и на условие коллинеарности , и :
concurrencyCondition(a, b, c) * collinearityCondition(A1, B1, C1) * collinearityCondition(A2, B2, C2) - условие коллинеарности , и :
collinearityCondition(Aprime, Bprime, Cprime)
Теперь давайте проверим их равенство:
calculate {
val condition1 = concurrencyCondition(a, b, c) * collinearityCondition(A1, B1, C1) * collinearityCondition(A2, B2, C2)
val condition2 = collinearityCondition(Aprime, Bprime, Cprime)
println(condition1 eq condition2)
println()
}
(calculate нужен, чтобы войти в область работы с многочленами, т.е. чтобы их умножать и приравнивать.)
Выведется true.
Т.е. многочлены абсолютно равны (а не просто пропорциональны).
Это чудо означает, что первое условие выполняется (т.е. его многочлен зануляется) тогда и только тогда, когда выполняется второе условие. При этом первое условие выполняется, когда выполняется хотя бы одно из следующих условий:
- , и конкурентны,
- , и коллинеарны,
- , и коллинеарны. Если отбросить второй и третий пункт, то получим исходную требуемую равносильность. При этом эти два пункта просто указывают на возможные вырождаемости рисунка, при которых достигается коллинеарность , и . Но все предполагают, что всё-таки рисунок не вырожден с самого начала, поэтому всё хорошо. Теорема доказана!
Завершение
Этот эксперимент не является каким-то цельным сюжетом, а состоит из множества мелких сюжетов. Больше сюжетов можно найти в других файлах этого проекта. Также этот фреймворк пока ещё является нестабильным, и есть довольно глобальные планы по его развитию. А вместе с этим пока не заканчивается и этот эксперимент.