Отношения эквивалентности и порядка

Два самых важных типа отношений: эквивалентность (что считать «одинаковым») и порядок (что раньше, что позже).

Отношение эквивалентности — отношение, которое одновременно рефлексивно, симметрично и транзитивно.

Зачем это нужно

Два отношения встречаются особенно часто, и у них есть имена. Эквивалентность отвечает на вопрос «что мы будем считать одним и тем же» — это основа хеш-таблиц, кеширования, дедупликации, сравнения объектов по содержимому. Порядок отвечает на вопрос «что идёт раньше» — это сортировка, приоритеты задач, версии, зависимости сборки (что собрать сначала). Понять эти два типа — значит понять, как компьютер группирует и упорядочивает данные.

Отношение эквивалентности: «считать одинаковым»

Отношение эквивалентности — это рефлексивность + симметричность + транзитивность вместе. Классический пример — сравнение по остатку от деления. Скажем, два числа «эквивалентны по модулю 3», если у них одинаковый остаток при делении на 3. Проверим три свойства:

  • Рефлексивность: у числа тот же остаток, что у него самого — очевидно.
  • Симметричность: если остаток a равен остатку b, то и наоборот.
  • Транзитивность: если остаток a = остаток b и остаток b = остаток c, то остаток a = остаток c.

Главная магия эквивалентности — классы эквивалентности. Класс элемента a — это все элементы, эквивалентные a. Эти классы не пересекаются и вместе покрывают всё множество, то есть образуют разбиение. Это глубокий и красивый факт: любое отношение эквивалентности разбивает множество на непересекающиеся классы, и наоборот — любое разбиение задаёт эквивалентность.

Смотрим классы на Python

from collections import defaultdict

# Эквивалентность: x ~ y, если x % 3 == y % 3 (одинаковый остаток на 3)
classes = defaultdict(list)
for x in range(10):
    classes[x % 3].append(x)

for r in sorted(classes):
    print(f"Класс [{r}] (остаток {r}):", classes[r])

Вывод:

Класс [0] (остаток 0): [0, 3, 6, 9]
Класс [1] (остаток 1): [1, 4, 7]
Класс [2] (остаток 2): [2, 5, 8]

Видно три непересекающихся класса, объединение которых — все числа от 0 до 9. Эти классы по модулю даже имеют имя — классы вычетов, и они станут основой модулярной арифметики в разделе о теории чисел.

Отношение порядка: «что раньше»

Отношение частичного порядка — это рефлексивность + антисимметричность + транзитивность. Сравни с эквивалентностью: симметричность заменена на антисимметричность. Смысл меняется кардинально: вместо «одинаковости» получаем «иерархию». Классический пример — отношение «делит» на множестве делителей числа, или «» на множестве множеств, или обычное «» на числах.

Слово «частичный» важно: некоторые пары элементов могут быть несравнимы. Например, в отношении «делит» числа 2 и 3 несравнимы: 2 не делит 3 и 3 не делит 2. Если же любые два элемента сравнимы (как у обычного на числах), порядок называют линейным (или полным). Сортировка возможна именно тогда, когда порядок линейный.

Диаграмма Хассе

Частичный порядок рисуют диаграммой Хассе: элементы — точки, и линия вверх от a к b, если b «следует сразу за» a (b больше a, и между ними нет ничего промежуточного). Рефлексивные петли и «выводимые по транзитивности» рёбра не рисуют — поэтому картинка чистая. Внизу диаграммы — минимальные элементы, наверху — максимальные.

Проверяем частичный порядок на Python

S = [1, 2, 3, 4, 6, 12]   # делители числа 12
def divides(a, b):
    return b % a == 0      # a делит b

refl = all(divides(a, a) for a in S)
antisym = all((not (divides(a, b) and divides(b, a))) or a == b
              for a in S for b in S)
trans = all((not (divides(a, b) and divides(b, c))) or divides(a, c)
            for a in S for b in S for c in S)
print("Рефлексивно:", refl, "Антисимметрично:", antisym, "Транзитивно:", trans)

# Минимальные и максимальные элементы
minimal = [a for a in S if all(a == b or not divides(b, a) for b in S)]
maximal = [a for a in S if all(a == b or not divides(a, b) for b in S)]
print("Наименьший элемент:", minimal)
print("Наибольший элемент:", maximal)

Вывод:

Рефлексивно: True Антисимметрично: True Транзитивно: True
Наименьший элемент: [1]
Наибольший элемент: [12]

Все три свойства выполнены — значит, «делит» на делителях 12 действительно частичный порядок. Минимальный элемент — 1 (делит всё), максимальный — 12 (делится на всё из набора). Но, например, 4 и 6 несравнимы — поэтому порядок частичный, а не линейный.

Сравнительная памятка

СвойствоЭквивалентностьЧастичный порядок
Рефлексивностьдада
Симметричностьданет (антисимметричность)
Транзитивностьдада
Что даётразбиение на классыиерархию, диаграмму Хассе

Транзитивное замыкание: достижимость в один присест

У отношений есть полезная операция — транзитивное замыкание: добавить к отношению все пары, которые «следуют по цепочке». Если из A можно дойти в B, а из B в C, то в замыкании появится и пара (A, C), даже если её не было исходно. Это в точности вопрос достижимости: представьте отношение «есть прямой рейс между городами» — его транзитивное замыкание отвечает на вопрос «можно ли долететь с пересадками».

Замыкание тесно связано с графами (отношение — это граф со стрелками) и вычисляется обходами или алгоритмом Уоршелла за O(n³). Эта идея работает повсюду: вычисление зависимостей в системах сборки (если A зависит от B, а B от C, то A зависит и от C), анализ наследования классов, поиск связанных компонентов. Так свойство «транзитивность», которое мы проверяли перебором пар, превращается в практический алгоритм достижимости.

Типичные ошибки

  • Считать любой порядок линейным. «Делит», «⊆», «зависит от» — частичные порядки: в них есть несравнимые пары. Линейный — это, например, на числах.
  • Забывать проверить все три свойства эквивалентности. «Похожесть» в быту часто не транзитивна (A похож на B, B на C, но A не похож на C) — и потому не является эквивалентностью.
  • Путать минимальный и наименьший элемент. В общем частичном порядке минимальных элементов может быть несколько, и они не обязаны быть «наименьшими» (сравнимыми со всеми).

Итог

  • Эквивалентность = рефлексивность + симметричность + транзитивность; разбивает множество на классы.
  • Частичный порядок = рефлексивность + антисимметричность + транзитивность; задаёт иерархию.
  • Порядок линейный, если любые два элемента сравнимы (тогда возможна сортировка).
  • Классы вычетов по модулю — важнейший пример эквивалентности, к нему мы ещё вернёмся.
Проверьте себя
1. Какие три свойства определяют отношение эквивалентности?
AРефлексивность, симметричность, транзитивность
BРефлексивность, антисимметричность, транзитивность
CСимметричность, антисимметричность, транзитивность
DРефлексивность, симметричность, антисимметричность
2. Что образуют классы эквивалентности на множестве?
AЛинейный порядок
BРазбиение множества на непересекающиеся части, покрывающие всё
CДекартово произведение
DПустое множество
3. Почему отношение «делит» на множестве {2, 3, 4, 6} — частичный, а не линейный порядок?
AОно не транзитивно
BОно не рефлексивно
CЕсть несравнимые элементы, например 2 и 3
DВ нём нет максимального элемента
Поддержать проект