ФЕДЕРАЛЬНОЕ АГЕНТСТВО ПО ОБРАЗОВАНИЮ
Федеральное государственное образовательное учреждение высшего профессионального образования
«ЮЖНЫЙ ФЕДЕРАЛЬНЫЙ УНИВЕРСИТЕТ»
Факультет математики, механики и компьютерных наук
Кафедра алгебры и дискретной математики
BMS-алгоритм и его применение в декодере
(направление подготовки 010500— Прикладная математика и информатика)
Магистерская диссертациястудента 2 курса магистратуры
Пеленицына Артема Михайловича
Научный руководитель:к.ф.-м.н., доцент
Владимир Михайлович Деундяк
Рецензент:доцент каф. ПОВТ и АС ДГТУ, к.т.н.
Надежда Сергеевна Могилевская
Рецензент:ст. преп. каф. ИВЭ ЮФУ, к.ф.-м.н.
Виктория Викторовна Махно
Ростов-на-Дону2009
Содержание
Введение 4
1 BMS-алгоритм 71.1 BM-алгоритм . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.2 Предварительные обозначения и конструкции для BMS-алго-
ритма . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.3 Схема BMS-алгоритма . . . . . . . . . . . . . . . . . . . . . . 161.4 Пример выполнения BMS-алгоритма . . . . . . . . . . . . . . 22
2 Реализация 252.1 Арифметический процессор . . . . . . . . . . . . . . . . . . . 262.2 Контейнерные структуры данных . . . . . . . . . . . . . . . 282.3 Реализация алгоритма . . . . . . . . . . . . . . . . . . . . . . 29
3 Применение BMS-алгоритма для декодирования АГ-кодовтипа кодов Рида—Соломона 313.1 АГ-коды типа кодов Рида—Соломона . . . . . . . . . . . . . 313.2 Метод декодирования АГ-кодов типа кодов Рида—Соломона
Юстесена—Ларсена—Йенсена—Хохольда . . . . . . . . . . . 333.3 Схема алгоритма декодирования . . . . . . . . . . . . . . . . 36
Заключение 37
Список литературы 38
Приложение 41
2
Введение
Теория помехоустойчивого кодирования является активно развивающей-ся областью науки и техники второй половины двадцатого, начала два-дцать первого века. Её задача была определена Клодом Шенноном в 1948году в статье «Математическая теория связи» [1], где были сформулирова-ны основные составляющие модели передачи данных по каналу с шумом.Алгебраическая теория кодирования, сформировавшаяся в 60–70-е гг., ре-шает задачу борьбы с помехами в канале алгебраическими методами. К80-м годам двадцатого века были открыты многочисленные классы поме-хоустойчивых кодов, некоторые из которых нашли широкое применение впрактике; из последних стоит отметить коды Рида–Соломона. В то же вре-мя теория кодирования пережила, наверное, самый большой переворот засвою историю связанный с применением алгебро-геометрических методовв конструировании кодов.
Первым заметившим, что аппарат алгебраической геометрии можно ис-пользовать для создания классов кодов с хорошими (не достигавшимисяранее) параметрами, был Гоппа [2]. Стоит также отметить фундаменталь-ную работу в этом направлении российских учёных Влэдуца и Цфасмана [3]1982 года. С конца 80-х и на протяжении 90-х количество работ, посвящен-ных этим вопросам, только возрастало. Упомянем серию публикаций груп-пы датских учёных по конструированию и декодированию одного классасравнительно простых с точки зрения использовавшихся фактов алгебра-ической геометрии кодов [16] [17] [28]. Надо признать, что в 2000-е центрвнимания профессионального сообщества сместился в сторону списочногодекодирования.
С наступлением «алгебро-геометрической эры» в кодировании стал во-прос о том, какие из классических подходов могут быть применены в но-вых условиях. Оказалось, что к таковым относится конструкция кодов Ри-да—Соломона и общий метод их декодирования, включая такой конструк-тивный элемент последнего как алгоритм Берлекэмпа—Месси (BM-алго-ритм). BM-алгоритм с момента своего появления в 1968 году получил ши-
3
рокое распространение не только для декодирования разнообразных клас-сов кодов теории помехоусточивого кодирования, но и в других областяхприкладной (например, криптография [4]) и фундаментальной (например,теория аппроксимаций Паде [11]) математики.
Обобщение BM-алгоритма для декодирования алгебро-геометрическихкодов связано с увеличением размерности задачи. Такое обобщение пред-ложил Саката [14], после чего алгоритм стал именоваться алгоритмом Бер-лекэмпа—Месси—Сакаты (BMS-алгоритмом). Он был применён для деко-дирования семейства кодов из [16], кроме того были разработаны болееобщие коды, для декодирования которых также может быть использованBMS-алгоритм [5].
Одной из проблем в области помехоустойчивого кодирования, основан-ного на фактах алгебраической геометрии, является сложность реализациирассматриваемых конструкций сравнительно с классическими (реализациикак программной, так и, в особенности, аппаратной).
Целью данной работы стала реализация BMS-алгоритма и изложениеподхода к его применению в декодировании АГ-кодов. Для достижения этойцели были поставлены задачи:
∙ изучение BMS-алгоритма, его связи с BM-алгоритмом и возможно-стей его реализации;
∙ разработка схемы BMS-алгоритма, которая может служить практи-ческим руководством к реализации;
∙ реализация BMS-алгоритма с использованием разработанной схемы;
∙ изучение АГ-кодов типа кодов Рида—Соломона и метода их декоди-рования [16] [17] [28];
∙ создание схемы декодера АГ-кодов типа кодов Рида—Соломона.
Результаты работы докладывались на конференции «Неделя науки»ЮФУ и X Международной научно-практической конференции «Информа-ционная безопасность» в г. Таганроге, тезисы опубликованы в соответству-
4
ющих сборниках [6] [7]. Часть результатов опубликована в издании, входя-щем в список ВАК [8].
Работа состоит из введения, трёх глав и приложения, содержащего ис-ходные коды выполненной реализации BMS-алгоритма.
5
1 BMS-алгоритм
1.1 BM-алгоритм
Первоначальная версия алгоритма Берлекэмпа—Месси (BM-алгоритма)была изложена Берлекэмпом в 1968 году [9] в качестве элемента конструк-ции декодера кодов Боуза—Чоудхудри—Хоквингема над конечным полем.Хотя в этой работе была указана возможность формулировки решаемойзадачи с использованием понятия линейного регистра сдвига с обратнойсвязью, алгоритм описывался исключительно в терминах полиномов и былвесьма сложен для понимания. Спустя год Месси [10] предложил свою ин-терпретацию алгоритма, который теперь строил линейный регистр сдвигаминимальной длины, генерирующий заданную последовательность элемен-тов конечного поля. Эта интерпретация оказалась полезной для более ши-рокого распространения алгоритма, получившего название по имени этихдвух ученых.
С момента появления алгоритма вышло немало работ, развивающих,обобщающих и по-новому интерпретирующих его идеи (например, [11] [13][25]). Рассматриваемый алгоритм находит применение при декодированииразличных классов кодов: кодов Рида—Соломона, кодов БЧХ, циклическихи обобщенных циклических кодов, альтернантных кодов и кодов Гоппы, и,наконец, наиболее общего и актуального на сегодня класса кодов — алгебро-геометрических кодов (вернее, некоторых их подклассов).
Построим структурную схему BM-алгоритма, следуя его описанию в [12].Последовательностью над полем F𝑞 будем называть любую функцию
𝑢 : N0 → F𝑞, заданную на множестве целых неотрицательных чисел и при-нимающую значения в этом поле.
Элементы последовательности 𝑢 будут обозначаться 𝑢(𝑖). Будет встре-чаться также понятие отрезка последовательности, которое получаетсяестественным образом из ограничения функции, упомянутой в определе-нии.
Последовательность 𝑢 будем называть линейной рекуррентной после-
6
довательностью (ЛРП) порядка 𝑚 > 0 над полем F𝑞, если существуютконстанты 𝑓0, ... , 𝑓𝑚−1 ∈ F𝑞 такие, что
𝑢(𝑖 + 𝑚) =𝑚−1∑︁𝑗=0
𝑓𝑗 · 𝑢(𝑖 + 𝑗), 𝑖 ≥ 0.
Указанное выражение назовем законом рекурсии или линейным рекуррент-ным соотношением. Говорят, что {𝑓𝑗}𝑚−1
𝑗=0 задают закон рекурсии для ЛРП 𝑢.Как видно, первые 𝑚 элементов последовательности не связаны какими-
либо ограничениями — они имеют особое значение, их, как правило, назы-вают начальным отрезком последовательности 𝑢.
Пусть 𝑢 — ЛРП, для которой {𝑓𝑗}𝑚−1𝑗=0 задают закон рекурсии. Много-
член:
𝐹 (𝑥) = 𝑥𝑚 −𝑚−1∑︁𝑗=0
𝑓𝑗 · 𝑥𝑗
с коэффициентами из поля F𝑞 назовем характеристическим многочленомЛРП 𝑢.
Таким образом, каждой ЛРП можно поставить в соответствие характе-ристический многочлен и обратно, каждому нормированному многочленуможно поставить в соответствие ЛРП. Можно показать однако, что одна ита же последовательность может задаваться разными законами рекурсиии, соответственно, иметь разные характеристические полиномы.
Характеристический полином ЛРП 𝑢, имеющий наименьшую степень,назовем её минимальным многочленом, а его степень — линейной сложно-стью ЛРП 𝑢.
Минимальные многочлены ЛРП, а также их линейная сложность, яв-ляются важными характеристиками ЛРП.
Пусть 𝑢 — последовательность над полем F𝑞. Обозначим через
𝑢(︀0, 𝑙 − 1
)︀= (𝑢(0), . . . , 𝑢(𝑙 − 1))
7
начальный отрезок 𝑢. Будем говорить, что многочлен
𝐺(𝑥) = 𝑥𝑚 −𝑚−1∑︁𝑗=0
𝑏𝑗 · 𝑥𝑗
вырабатывает отрезок 𝑢(︀0, 𝑙 − 1
)︀, если
∀𝑖 ∈ [0, 𝑙 −𝑚− 1] : 𝑢(𝑖 + 𝑚) =𝑚−1∑︁𝑗=0
𝑏𝑗 · 𝑢(𝑖 + 𝑗),
то есть если данный отрезок последовательности является отрезком неко-торой ЛРП с характеристическим многочленом 𝐺(𝑥).
Естественным образом определяется понятие линейной сложности от-резка последовательности как минимальной степени из всех полиномов,вырабатывающих данный отрезок.
Алгоритм Берлекэмпа—Месси строит многочлен 𝐺(𝑥) наименьшей сте-пени, вырабатывающий отрезок 𝑢
(︀0, 𝑙 − 1
)︀. Чтобы перейти к непосред-
ственному описанию алгоритма, требуется ввести ещё ряд вспомогательныхопределений.
Введём операцию умножения произвольного многочлена
𝐻(𝑥) =𝑛∑︁
𝑗=0
ℎ𝑗𝑥𝑗
на любую последовательность 𝑣, результатом которой будет последователь-ность 𝑤, такая что:
(𝐻(𝑥) · 𝑣)(𝑖) = 𝑤(𝑖)def=
𝑛∑︁𝑗=0
ℎ𝑗 · 𝑣(𝑖 + 𝑗)
Очевидно, операция является линейной относительно полинома, входя-щего в неё.
Для нормированного полинома 𝐺(𝑥) определим параметры:
1. 𝑘𝑢(𝐺) — количество лидирующих нулей последовательности 𝐺(𝑥) · 𝑢
8
или ∞, если эта последовательность нулевая.
2. 𝑙𝑢(𝐺) = 𝑘𝑢(𝐺) + deg(𝐺).
Легко убедиться, что 𝑙𝑢(𝐺) — максимальная длина начального отрезка𝑢, вырабатываемого 𝐺(𝑥). Действительно, пусть
𝐺(𝑥) =𝑚∑︁𝑗=0
𝑔𝑗 · 𝑥𝑗 = 𝑥𝑚 −𝑚−1∑︁𝑗=0
𝑏𝑗 · 𝑥𝑗.
Обозначим 𝐺(𝑥) · 𝑢 = 𝑣. Тогда:
∀𝑖 ∈ [0, 𝑙𝑢(𝐺) −𝑚− 1] : 𝑣(𝑖) = 0,
но:
0 = 𝑣(𝑖) =𝑛∑︁
𝑗=0
𝑔𝑗 · 𝑢(𝑖 + 𝑗) = 𝑢(𝑖 + 𝑚) −𝑚−1∑︁𝑗=0
𝑏𝑗 · 𝑢(𝑖 + 𝑗),
что и дает искомое:
∀𝑖 ∈ [0, 𝑙𝑢(𝐺) −𝑚− 1] : 𝑢(𝑖 + 𝑚) =𝑚−1∑︁𝑗=0
𝑏𝑗 · 𝑢(𝑖 + 𝑗).
Теперь можно привести полную схему классического BM-алгоритма. За-дадимся последовательностью 𝑢 над полем F𝑞 и числом 𝑙. Найдем мини-мальный полином 𝐺(𝑥), вырабатывающий отрезок 𝑢
(︀0, 𝑙 − 1
)︀, используя
BM-алгортим, описываемый нижеследующей структурной схемой, постро-енной по работе [12].
9
Вход: 𝑢, 𝑙
𝐺0(𝑥) := 1, 𝑙0 := 𝑙𝑢(𝐺0)
𝑙0 < 𝑙
𝐺1(𝑥) := 𝑥𝑘0+1− 𝑢0(𝑘0 + 1)𝑢0(𝑘0)−1𝐺0(𝑥),
𝑙1:=𝑙𝑢(𝐺1), 𝑡:=1
𝑙𝑡 < 𝑙
определим 𝑠 из соотношения:𝑚𝑡 = 𝑚𝑡−1 = . . . = 𝑚𝑠+1 > 𝑚𝑠
𝑘𝑡 > 𝑘𝑠
𝐺𝑡+1(𝑥) := 𝑥𝑘𝑡−𝑘𝑠𝐺𝑡(𝑥) − 𝑢𝑡(𝑘𝑡)𝑢𝑠(𝑘𝑠)−1𝐺𝑠(𝑥)
𝐺𝑡+1(𝑥) := 𝐺𝑡(𝑥) − 𝑥𝑘𝑡−𝑘𝑠𝑢𝑡(𝑘𝑡)𝑢𝑠(𝑘𝑠)−1𝐺𝑠(𝑥)
𝑙𝑡+1 := 𝑙𝑢(𝐺𝑡+1), 𝑡 := 𝑡 + 1
𝐺(𝑥) := 𝐺𝑡(𝑥)
Выход: 𝐺(𝑥)
Да
Да
Нет
Нет
ДаНет
10
1.2 Предварительные обозначения и конструкции для
BMS-алгоритма
Введём обозначения для следующих множеств: N0 = {0, 1, 2, . . .}, Σ0 =
N20. Элементы Σ0 будем называть точками и выделять полужирным шриф-
том, например: 𝑛 ∈ Σ0. Компоненты точек будем обозначать нижними ин-дексами, например, компоненты точки 𝑛: 𝑛1, 𝑛2. Для точек Σ0 определенопокомпонентное сложение:
∀𝑛,𝑚 ∈ Σ0 : 𝑛 + 𝑚def= (𝑛1 + 𝑚1, 𝑛2 + 𝑚2).
Аналогично будем использовать вычитание точек, когда оно корректно (обекоординаты уменьшаемого не меньше соответствующих координат вычита-емого).
Сумма точки и множества точек определяется так:
∀𝑠 ∈ Σ0 ∀𝑀 ⊂ Σ0 : 𝑠 + 𝑀def= {𝑠 + 𝑚 | 𝑚 ∈ 𝑀}.
Введём два отношения порядка на Σ0:
1. ∀𝑚,𝑛 ∈ Σ0 : 𝑚 < 𝑛 тогда и только тогда, когда
(𝑚1 6 𝑛1) ∧ (𝑚2 6 𝑛2) ∧ (𝑚 ̸= 𝑛);
2. ∀𝑚,𝑛 ∈ Σ0 : 𝑚 <T 𝑛 тогда и только тогда, когда
(︀𝑚1 + 𝑚2 < 𝑛1 + 𝑛2
)︀∨
(︀(𝑚1 + 𝑚2 = 𝑛1 + 𝑛2) ∧ (𝑚2 < 𝑛2)
)︀. (1)
Первое отношение является отношением частичного порядка, а второе —отношением линейного порядка. Естественным образом определяются ре-флексивные версии этих отношений («нестрогие неравенства»): 6,6T. Бу-дут использоваться также обозначения 𝑚 ̸< 𝑛 и 𝑚 ̸6 𝑛, когда выполненоодно из неравенств 𝑚1 > 𝑛1 или 𝑚2 > 𝑛2, или оба сразу.
11
Линейный порядок позволяет для каждой точки 𝑛 единственным обра-зом определить непосредственно следующую за ней точку 𝑛′ :
∀𝑛 ∈ Σ0 : 𝑛′ =
{︃(𝑛1 − 1, 𝑛2 + 1), если 𝑛1 > 0,
(𝑛2 + 1, 0), если 𝑛1 = 0.
Введём множества:
∀𝑚 ∈ Σ0 : Σ𝑚def= {𝑝 ∈ Σ0 | 𝑚 ≤ 𝑝};
∀𝑚,𝑛 ∈ Σ0 : Σ𝑛𝑚
def= {𝑝 ∈ Σ0 | (𝑚 ≤ 𝑝) ∧ (𝑝 <T 𝑛)}.
Отметим, что если 𝑛 6T 𝑚, то множество Σ𝑛𝑚 пусто. Кроме того, обратим
особое внимание, что 𝑛 ̸∈ Σ𝑛𝑚.
Пусть задано поле Галуа F𝑞. Полином от двух переменных над полемF𝑞, т. е. элемент кольца F𝑞[𝑥]
def= F𝑞[𝑥1, 𝑥2], будем записывать так:
𝑓(𝑥) =∑︁𝑚∈Γ𝑓
𝑓𝑚 · 𝑥𝑚,
где 𝑥𝑚 = 𝑥𝑚11 · 𝑥𝑚2
2 , 𝑓𝑚 ∈ F𝑞, а конечное множество
Γ𝑓 = {𝑚 ∈ Σ0 | 𝑓𝑚 ̸= 0}
— носитель множества коэффициентов. Линейный порядок на Σ0 позволя-ет корректно определить (старшую) степень полинома 𝑓 , которую будемобозначать LP(𝑓):
∀𝑓 ∈ F𝑞[𝑥] : LP(𝑓)def= max
𝑚∈Γ𝑓
𝑚,
где максимум берется в смысле линейного порядка на Σ0. Для произволь-ного (упорядоченного) набора полиномов ℱ = {𝑓 (𝑖)(𝑥)}𝑙𝑖=1 определим:
LP(ℱ)def= {𝑠(𝑖) = LP(𝑓 (𝑖))}𝑙𝑖=1
Конечной двумерной последовательностью (или просто последователь-
12
ностью) 𝑢 «длины» 𝑝 ∈ Σ0 над полем F𝑞 назовем отображение
𝑢 : Σ𝑝0 → F𝑞.
Ограничение этого отображения на множество Σ𝑛0 для некоторого 𝑛 ∈ Σ𝑝′
0
обозначим 𝑢𝑛 и назовем 𝑛-срезкой 𝑢. Отметим, что 𝑛-срезка 𝑢 в свою оче-редь является двумерной последовательностью длины 𝑛.
Для полинома 𝑓 степени 𝑠, последовательности 𝑢 длины 𝑝 и точки 𝑛 ∈Σ𝑝
𝑠 определим элемент поля F𝑞:
𝑓 [𝑢]𝑛def=
∑︁𝑚∈Γ𝑓
𝑓𝑚 · 𝑢𝑚+𝑛−𝑠. (2)
Напомним, что в случае 𝑝 6T 𝑠 множество Σ𝑝𝑠 пусто. Будем писать 𝑓 ∈
VALPOL(𝑢) тогда и только тогда, когда
∀𝑛 ∈ Σ𝑝𝑠 : 𝑓 [𝑢]𝑛 = 0. (3)
Таким образом, в случае 𝑝 6T 𝑠 условие 𝑓 ∈ VALPOL(𝑢) выполнено три-виально.
Очевидно, для любой последовательности 𝑢 длины 𝑝 выполнено:
∀𝑚,𝑛 ∈ Σ𝑝′
0 : 𝑚 <T 𝑛 ⇒ VALPOL(𝑢𝑚) ⊃ VALPOL(𝑢𝑛)
Уточним этот факт для случая последовательно идущих точек:
∀𝑛 ∈ Σ𝑝0 ∀𝑓 ∈ VALPOL(𝑢𝑛) :
𝑓 ∈ VALPOL(𝑢𝑛′) ⇔
(︀𝑛 ̸∈ Σ𝑛′
LP(𝑓)
)︀∨(︀𝑓 [𝑢]𝑛 = 0
)︀.
Действительно, ∀𝑠,𝑛 ∈ Σ0 : Σ𝑛′
𝑠 ∖Σ𝑛𝑠 ⊂ {𝑛}. Таким образом, надо рассмот-
реть два случая:
1. Σ𝑛′
LP(𝑓) ∖ Σ𝑛LP(𝑓) = ∅, т. е. Σ𝑛′
LP(𝑓) = Σ𝑛LP(𝑓), тогда по определению
𝑓 ∈ VALPOL(𝑢𝑛) ⇒ 𝑓 ∈ VALPOL(𝑢𝑛′).
13
2. Σ𝑛′
LP(𝑓) ∖ Σ𝑛LP(𝑓) = {𝑛}, тогда
𝑓 ∈ VALPOL(𝑢𝑛′) ⇔
∀𝑚 ∈ Σ𝑛′
𝐿𝑃 (𝑓) = Σ𝑛𝐿𝑃 (𝑓) ∪ {𝑛} : 𝑓 [𝑢]𝑚 = 0 ⇔
𝑓 ∈ VALPOL(𝑢𝑛) ∧ 𝑓 [𝑢]𝑛 = 0. (4)
Назовём набор точек {𝑠(𝑖)}𝑙𝑖=1 набором гиперболического типа (или про-сто гиперболическим набором), если для него выполнены соотношения:
𝑠(1)1 > 𝑠
(2)1 > . . . > 𝑠
(𝑙)1 = 0, 0 = 𝑠
(1)2 < 𝑠
(2)2 < . . . < 𝑠
(𝑙)2 . (5)
Каждому гиперболическому набору точек {𝑠(𝑖)}𝑙𝑖=1 поставим в соответствиемножество ∆ = ∆({𝑠(𝑖)}𝑙𝑖=1), определяемое по формуле:
∆({𝑠(𝑖)}𝑙𝑖=1) = Σ0 ∖ (Σ𝑠(1) ∪ Σ𝑠(2) ∪ . . . ∪ Σ𝑠(1)),
Множество ∆ = ∆({𝑠(𝑖)}𝑙𝑖=1) в этом случае назовем ∆-множеством длянабора {𝑠(𝑖)}𝑙𝑖=1. В свою очередь набор {𝑠(𝑖)}𝑙𝑖=1 называется определяющимиточками ∆.
Если для некоторого упорядоченного набора полиномов
ℱ = {𝑓 (𝑖)(𝑥)}𝑙𝑖=1
их степениLP(ℱ) = {𝑠(𝑖)}𝑙𝑖=1
составляют гиперболический набор, то ∆(LP(ℱ)) мы будем обозначать про-сто ∆(ℱ).
Пусть дана конечная двумерная последовательность 𝑢 «длины» 𝑝. Ми-нимальным множеством (полиномов) для последовательности 𝑢 называ-ется набор ℱ = {𝑓 (𝑖)(𝑥)}𝑙𝑖=1, удовлетворяющий условиям:
1. ℱ ⊂ VALPOL(𝑢).
14
2. LP(ℱ) — гиперболический набор.
3. ∀𝑔 ∈ F𝑞[𝑥] : 𝑔 ∈ VALPOL(𝑢) ⇒ LP(𝑔) /∈ ∆(ℱ).
Условие (3) гарантирует единственность гиперболического набора, за-даваемого любым минимальным множеством для данной последовательно-сти. Если ℱ — некоторое минимальное множество для последовательности𝑢, то ∆(ℱ) можно обозначить ∆(𝑢). Существование минимального множе-ства для последовательности будет доказано конструктивно — описаниемалгоритма, строящего его.
1.3 Схема BMS-алгоритма
Данный алгоритм, разработанный Сакатой в [14] на основе модифи-кации классического алгоритма Берлекэмпа–Месси, строит минимальноемножество полиномов 𝐹 для произвольной последовательности 𝑢 «длины»𝑝. Перед тем как описать шаги алгоритма, нужно ввести некоторые мно-жества, с которыми работает алгоритм, и дополнительные обозначения.
Алгоритм имеет итеративный характер: на каждой итерации значениепараметра 𝑛 ∈ Σ0 («мультиномер итерации») заменяется на точку, непо-средственно следующую за 𝑛. Как только 𝑛 станет равным 𝑝 (длине по-следовательности), алгоритм завершится.
К началу 𝑛-ой итерации сформированы:
𝐹 = {𝑓 (𝑖)(𝑥)}𝑙𝑖=1 — минимальное множество для 𝑛-срезки 𝑢;
𝐺 = {𝑔(𝑖)(𝑥)}𝑙−1𝑖=1 — вспомогательное множество полиномов, такое что:
∀𝑖 ∈ [1, 𝑙 − 1] ∃𝑝(𝑖) ∈ Σ𝑛0 : 𝑔(𝑖) ∈ VALPOL(𝑢𝑝
(𝑖)
) ∖ VALPOL(𝑢𝑝(𝑖)′
),
в частности, 𝑑(𝑖)def= 𝑔(𝑖)[𝑢]𝑝(𝑖) ̸= 0. Более точно: 𝑔(𝑖) входил в 𝐹 на
итерации 𝑝(𝑖), но не мог входить в него при переходе к 𝑝(𝑖)′ из-за того,что 𝑑(𝑖) ̸= 0.
С 𝐹 связано множество:
15
𝑆 = {𝑠(𝑖)}𝑙𝑖=1 = LP(𝐹 ),
с 𝐺 связаны три множества:
𝑇 = {𝑡(𝑖)}𝑙−1𝑖=1 = LP(𝐺),
𝑃𝐺 = {𝑝(𝑖)}𝑙−1𝑖=1,
𝐷𝐺 = {𝑑(𝑖)}𝑙−1𝑖=1.
Введём следующие обозначения, которые используют перечисленныепараметры алгоритма и, таким образом, зависят от мультиномера текущейитерации 𝑛:
(1) Опишем число inSD(𝑠) ∈ [0, 𝑙 − 1]N0для любого 𝑠 ∈ Σ0:
если 𝑛 ̸∈ 𝑠 + ∆(𝐹 ), положим inSD(𝑠)def= 0,
если 𝑛 ∈ 𝑠 + ∆(𝐹 ), то ∃𝑖 ∈ [1, 𝑙 − 1]N0, такой что:
(𝑛1 < 𝑠1 + 𝑠(𝑖)1 ) ∧ (𝑛2 < 𝑠2 + 𝑠
(𝑖+1)2 ),
любой из таких 𝑖 обозначим inSD(𝑠).
Замечание 1 inSD — «in shifted Delta-set», «в сдвинутом дельта-множестве»: мультиномер 𝑛 текущей итерации находится в сдви-нутом на 𝑠 ∆-множестве.
(2) ∀𝑖 ∈ [1, 𝑙]N, 𝑗 ∈ [0, 𝑙 − 1]N0:
BP⟨𝑖, 𝑗⟩ def=
{︃𝑓 (𝑖), 𝑗 = 0;𝑥𝑟−𝑠(𝑖) · 𝑓 (𝑖) − (𝑑/𝑑(𝑗))𝑥𝑟−𝑛+𝑝(𝑗)−𝑡(𝑗) · 𝑔(𝑗), иначе,
где 𝑑 = 𝑓 (𝑖)[𝑢]𝑛, 𝑟𝑘 = max{𝑠(𝑖)𝑘 ; 𝑡(𝑗)𝑘 + 𝑛𝑘 − 𝑝
(𝑗)𝑘 }, 𝑘 ∈ {1, 2};
(3) ∀𝑖 ∈ [1, 𝑙]N ∀𝑘 ∈ {1, 2}:
SP𝑘⟨𝑖⟩def= 𝑥
𝑛𝑘−𝑠(𝑖)𝑘 +1
𝑘 · 𝑓 (𝑖);
16
Вход: двумерная последовательность 𝑢 длины 𝑝 над полем F𝑞.Выход: минимальное множество 𝐹 для 𝑢.
Шаг 0. Положить 𝑛 := (0, 0), 𝐹 := {1} (∆(𝐹 ) = ∅), 𝐺 := 𝐷𝐺 := 𝑃𝐺 := ∅.
Замечание 2 Инициализация параметров алгоритма совпадает с [14,п. 5, шаг 1].
Шаг 1. ∀𝑖 ∈ [1, 𝑙]N:
if 𝑠(𝑖) ̸6 𝑛 ∨ 𝑓 (𝑖)[𝑢]𝑛 = 0 then 𝑓 (𝑖) ∈ 𝐹𝑉 else 𝑓 (𝑖) ∈ 𝐹𝑁 .
Замечание 3 Множества 𝐹𝑉 , 𝐹𝑁 ⊂ 𝐹 вводятся в [14] после тео-ремы 1, п. 4. 𝐹𝑉 — множество полиномов, которые не требуют из-менения на текущей итерации (V — valid, эффективный, действи-тельный). 𝐹𝑁 — множество полиномов, которые необходимо моди-фицировать на данной итерации (N — nonvalid).
Замечание 4 Условие 𝑠(𝑖) ̸6 𝑛 влечёт за собой 𝑛 ̸∈ Σ𝑛′
𝑠(𝑖). Как указа-
но в (4), этот факт вместе с имеющимся к началу 𝑛-ой итерации𝑓 (𝑖) ∈ VALPOL(𝑢𝑛) влечет за собой 𝑓 (𝑖) ∈ VALPOL(𝑢𝑛
′). Этот слу-
чай не обсуждается в [14].
Шаг 2. Введём 𝑎𝑢𝑥 := 0𝑙 — вектор из 𝑙 компонент, пока нулевой.
∀𝑓 (𝑖) ∈ 𝐹𝑁 : 𝑎𝑢𝑥[𝑖] := inSD(𝑠(𝑖)),
где 𝑎𝑢𝑥[𝑖] — 𝑖-ая компонента вектора 𝑎𝑢𝑥.
Шаг 3. if ∀𝑓 (𝑖) ∈ 𝐹𝑁 : 𝑎𝑢𝑥[𝑖] ̸= 0 then
∀𝑓 (𝑖) ∈ 𝐹𝑁 : 𝑓 (𝑖) := BP⟨𝑖, 𝑎𝑢𝑥[𝑖]⟩; gotoШаг 8.
17
Замечание 5 Условие шага 3 взято непосредственно из описанияалгоритма [14, п. 5, шаг 2]. Отличие состоит в использовании вспо-могательного вектора 𝑎𝑢𝑥, хранящего сразу все результаты прове-рок 𝑛 ∈ LP(𝑓 (𝑖)) + ∆ (выполняемых в этом месте в [14]) и исполь-зовании нашего обозначения inSD(𝑛)𝑠 (шаг 2) для этих проверок.
Замечание 6 Формула для пересчёта 𝑓 (𝑖) вытекает из теоремы 1в [14, п. 4], а верней, её обоснования, приведенного перед формули-ровкой. Использование теоремы 1 продиктовано [14, п. 5, шаг 2].
Шаг 4. Построить следующие множества точек:
∆1 = {(𝑠(𝑖)1 , 𝑠
(𝑖)2 ) | 𝑖 ∈ [1, 𝑙]N ∧
(︁𝑓 (𝑖) ∈ 𝐹𝑉 ∨ 𝑎𝑢𝑥[𝑖] ̸= 0
)︁};
∆2 = {(𝑛1 − 𝑠(𝑖)1 + 1, 𝑛2 − 𝑠
(𝑖+1)2 + 1) | 𝑖 ∈ [1, 𝑙 − 1]N∧
𝑓 (𝑖), 𝑓 (𝑖+1) ∈ 𝐹𝑁};
∆3 = {(𝑛1 − 𝑠(𝑖)1 + 1, 𝑠
(𝑗)2 ) | 𝑖, 𝑗 ∈ [1, 𝑙]N∧
(𝑓 (𝑖), 𝑓 (𝑗) ∈ 𝐹𝑁) ∧ (𝑠(𝑖) + 𝑠(𝑗) 6 𝑛)∧
(∀𝑘 ∈ (𝑖, 𝑙]N : 𝑛2 < 𝑠(𝑘)2 + 𝑠
(𝑗)2 )};
∆4 = {(𝑠(𝑖)1 , 𝑛2 − 𝑠
(𝑗)2 + 1) | 𝑖, 𝑗 ∈ [1, 𝑙]N∧
(𝑓 (𝑖), 𝑓 (𝑗) ∈ 𝐹𝑁) ∧ (𝑠(𝑖) + 𝑠(𝑗) 6 𝑛)∧
∀𝑘 ∈ [1, 𝑗)N : 𝑛1 < 𝑠(𝑘)1 + 𝑠
(𝑖)1 }.
∆new = ∆1 ∪ ∆2 ∪ ∆3 ∪ ∆4.
Замечание 7 Необходимость построения нового ∆-множества (ав след за ним и нового 𝐹 — см. следующий шаг) указывается в [14,
18
п. 5, шаг 2] со ссылкой на теорему 2. В теореме 2 описываетсяпостроение нового 𝐹 по ∆𝑒(𝑢
𝑛′) — множеству «исключённых то-
чек». Последнее составляют точки, которые обладают таким свой-ством: ¬∃𝑓 ∈ VALPOL(𝑢𝑛
′) : LP(𝑓) ∈ ∆𝑒(𝑢
𝑛′). Фактически на на-
шем шаге 4 строится ∆𝑒(𝑢𝑛′
), но так как теорема 2 указываетспособ построения полиномов, старшие степени которых являют-ся определяющими точками ∆𝑒(𝑢
𝑛′), то ∆𝑒(𝑢
𝑛′) = ∆(𝑢𝑛
′).
Замечание 8 Множество ∆𝑒(𝑢𝑛) определяется в [14, стр. 327], ос-
новываясь на лемме 4. По построению видно, что ∆𝑒(𝑢𝑛) это ∆-
множество.
Замечание 9 Условия включения точек каждого из четырех ти-пов описаны в [14]: Леммы 8 и 9 и предшествующие им рассуждения(после теоремы 1). Сами четыре типа перечислены в Лемме 7 [14].
Замечание 10 В соответствии с определением ∆-множества (см. (5)),при построении ∆3 и ∆4 можно рассматривать лишь 𝑘 = 𝑖 + 1 и𝑘 = 𝑗 − 1 соответственно. Эта оптимизация не указана в [14].
Замечание 11 Информация об элементах ∆𝑟 включает не толькоточку Σ0, но и «историю появления» этой точки, то есть числа 𝑖,𝑗.
Шаг 5. Построить следующие множества полиномов.𝐹1 = {BP⟨𝑖, 𝑎𝑢𝑥[𝑖]⟩ | (𝑠
(𝑖)1 , 𝑠
(𝑖)2 ) ∈ ∆1};
𝐹2 = {BP⟨𝑘, 𝑖⟩ | (𝑛1 − 𝑠(𝑖)1 + 1, 𝑛2 − 𝑠
(𝑖+1)2 + 1) ∈ ∆2,
𝑘 : 𝑓 (𝑘) ∈ 𝐹𝑁 ∧ 𝑠(𝑘) < 𝑡};
𝐹3 = {BP⟨𝑗, 𝑖⟩ | (𝑛1 − 𝑠(𝑖)1 + 1, 𝑠
(𝑗)2 ) ∈ ∆3 ∧ 𝑖 ̸= 𝑙} ∪
{SP1⟨𝑗⟩ | (𝑛1 + 1, 𝑠(𝑗)2 ) ∈ ∆3}
19
𝐹4 = {BP⟨𝑖, 𝑗 − 1⟩ | (𝑠(𝑖)1 , 𝑛2 − 𝑠
(𝑗)2 + 1) ∈ ∆4 ∧ 𝑗 ̸= 1} ∪
{SP2⟨𝑖⟩ | (𝑠(𝑖)1 , 𝑛2 + 1) ∈ ∆4}
𝐹new = 𝐹1 ∪ 𝐹2 ∪ 𝐹3 ∪ 𝐹4.
Замечание 12 Построение 𝐹new с точностью до обозначений и груп-пировки случаев C и D, а также E и F (для рассмотрения, соответ-ственно, точек типа (3) и (4)), следует теореме 2 [14].
Замечание 13 Точки типа (1), согласно рассуждениям, следующимза теоремой 1 [14], появляются в случаях если полином, которыйобеспечил её вхождение в ∆new (назовём его 𝑓 (𝑖)) либо лежит в 𝐹𝑉
либо может быть переведён в VALPOL(𝑢(𝑛′)) с помощью теоре-
мы 1 [14]. В первом случае соответствующая компонента векотра𝑎𝑢𝑥 равна 0 (по построению) и формула BP⟨𝑖, 𝑎𝑢𝑥[𝑖]⟩ = BP⟨𝑖, 0⟩ =
𝑓 (𝑖) оставит полином неизменным, во втором случае эта формулав точности реализует теорему 1 [14].
Замечание 14 Существование 𝑘 из построения полинома для то-чек типа (2) упоминается непосредственно в теореме 2 [14] со ссыл-кой на доказательство леммы 8.
Шаг 6. Построить 𝐺new, исходя из условий: 𝐺new ⊂ 𝐺∪𝐹𝑁 и |𝐺new| = |𝐹new|−1.Пронумеровать элементы 𝐺new, следуя следующему правилу. Каждыйполином 𝑔 ∈ 𝐺new получает номер 𝑖 ∈ [1, 𝑙 − 1]N, если выполненоусловие:
𝑠(𝑖+𝑘−1)𝑘 = 𝑟𝑘 − 𝑡𝑘 + 1, (6)
где 𝑘 ∈ {1, 2}, 𝑡 = LP(𝑔) и
𝑟 =
{︃𝑝(𝑖) ∈ 𝑃𝐺, если 𝑔 ∈ 𝐺;𝑛, если 𝑔 ∈ 𝐹𝑁 .
(7)
20
Замечание 15 Условие 𝐺new ⊂ 𝐺 ∪ 𝐹𝑁 указано в [14, п. 5, шаг 2].Условие |𝐺new| = |𝐹new|−1 взято из определения 𝐺. Формула (6) взя-та из [14, (12)], с учетом, что для 𝑔 ∈ 𝐹𝑁 (элементов 𝐺, добавив-шихся на текущей итерации) в роли 𝑝(𝑖) выступает мультиномертекущей итерации — 𝑛.
Шаг 7. Построить множества 𝑇new, 𝑃𝐺new, 𝐷𝐺new для 𝐺new, следуя описанию𝑇 , 𝑃𝐺 и 𝐷𝐺. Поясним способ построения 𝑃𝐺new: если 𝑔(𝑖) из 𝐺new
принадлежит 𝐺, то его параметр 𝑝(𝑖) просто берется из 𝑃𝐺, в против-ном случае, если он принадлежит 𝐹𝑁 , то его параметр 𝑝(𝑖) полагаетсяравным 𝑛.
Заменить 𝐹,𝐺, 𝑇, 𝑃𝐺,𝐷𝐺 на 𝐹new, 𝐺new, 𝑇new, 𝑃𝐺new, 𝐷𝐺new.
Шаг 8. 𝑛 := 𝑛′;if 𝑛 = 𝑝 then exit; else gotoШаг 1.
Замечание 16 Условие окончания или продолжения алгоритма сов-падает с указанным в [14, п. 5, шаг 3].
1.4 Пример выполнения BMS-алгоритма
Рассмотрим следующую последовательность 𝑢 : Σ(5,1)0 → F2 = {0, 1} [14]:
𝑢(0,0) = 0, 𝑢(0,1) = 1, 𝑢(0,2) = 0,
𝑢(1,0) = 1, 𝑢(1,1) = 1,
𝑢(2,0) = 0,
𝑢(3,0) = 0.
Применим к ней BMS-алгоритм, используя схему, построенную в предыду-щем разделе. Назовём «итерацией алгоритма» один проход по шагам 1–8 ибудем нумеровать итерации римскими цифрами. Номера шагов в соответ-ствии со схемой будут обозначаться арабскими цифрами.
21
Некоторые шаги данной итерации, на которых делать ничего не потре-буется, будем пропускать, не оговаривая это каждый раз особо. Например,если после шага 1 𝐹𝑁 = ∅, то надо сразу переходить на шаг 8 (по goto изшага 3).
Пусть заданы начальные значения из шага 0: 𝑛 := (0, 0), 𝐹 := {𝑓 (1) =
1}, (∆(𝐹 ) = ∅), 𝐺 := 𝐷𝐺 := 𝑃𝐺 := ∅.
I. Шаг 1. 𝑠(1) = (0, 0) 6 𝑛 = (0, 0).
𝑓 (1)[𝑢](0,0) = 𝑓(0,0)𝑢(0,0) = 1 · 0 = 0 =⇒ 𝑓 (1) ∈ 𝐹𝑉 . 𝐹𝑁 = ∅.
Условие шага 3 выполнено тривиально (𝐹𝑁 = ∅). Перейдём на шаг 8.
Шаг 8. 𝑛 := (0, 1).
II. Шаг 1. 𝑠(1) = (0, 0) 6 𝑛 = (1, 0)
𝑓 (1)[𝑢](1,0) = 𝑓(0,0)𝑢(1,0) = 1 =⇒ 𝑓 (1) ∈ 𝐹𝑁 .
Шаг 2 Вычислим 𝑎𝑢𝑥[1]:
∆ = ∅ ⇒ 𝑛 ̸∈ LP(𝑓 (1)) + ∆(= ∅) ⇒ inSD(𝑠(1)) = 0 ⇒ 𝑎𝑢𝑥[1] = 0.
Условие шага 3 не выполнено. Переходим на шаг 4.
Шаг 4. ∆1 = ∆2 = ∅, ∆3 = {(1, 0)} (𝑖 = 𝑗 = 1), ∆3 = {(1, 0)}(𝑖 = 𝑗 = 1).
Шаг 5. 𝐹3 = {𝑥𝑛1−𝑠(1)1 +1
1 𝑓 (1) = 𝑥21}, 𝐹4 = {𝑥𝑛2−𝑠(1)2 +1
2 𝑓 (1) = 𝑥2}.
Шаг 6. 𝐺new = 𝑔(1) = 1.
Шаг 7. 𝑃𝐺new = {𝑝(1) = (1, 0)}, 𝐷𝐺new = {𝑑(1) = 1}. 𝐹 = {𝑓 (1) =
𝑥21; 𝑓(2) = 𝑥2}, ∆ = {(0, 0); (1, 0)}.
Шаг 8. 𝑛 := (0, 1).
III. Шаг 1. 𝑠(1) = (2, 0) ̸6 𝑛 = (0, 1) =⇒ 𝑓 (1) ∈ 𝐹𝑉 .𝑠(2) = (0, 1) 6 𝑛 = (0, 1).𝑓 (2)[𝑢](0,1) = 𝑓(0,1)𝑢(0,1) = 1 · 1 = 1 =⇒ 𝑓 (2) ∈ 𝐹𝑁 .
Шаг 2. 𝑛 = (0, 1) ∈ 𝑠(2) + ∆ = {(0, 1); (1, 1)} =⇒ 𝑎𝑢𝑥[2] = 1.
22
Шаг 3. Условие выполнено. 𝑓 (2) := BP⟨2, 1⟩ = 𝑥2 + 𝑥1.
Шаг 8. 𝑛 := (2, 0) (𝐹 = {𝑓 (1) = 𝑥21; 𝑓(2) = 𝑥2 + 𝑥1}).
IV. Шаг 1. 𝑠(1) = (2, 0) 6 𝑛 = (2, 0).𝑓 (1)[𝑢](2,0) = 𝑓(2,0)𝑢(2,0) = 1 · 0 = 0 =⇒ 𝑓 (2) ∈ 𝐹𝑉 .𝑠(2) = (0, 1) ̸6 𝑛 = (2, 0) =⇒ 𝑓 (2) ∈ 𝐹𝑉 .
Шаг 8. 𝑛 := (1, 1).
V. Шаг 1. 𝑠(1) = (2, 0) ̸6 𝑛 = (1, 1) =⇒ 𝑓 (1) ∈ 𝐹𝑉 .𝑠(2) = (0, 1) 6 𝑛 = (1, 1).
𝑓 (2)[𝑢](1,1) =∑︁
𝑓𝑚𝑢𝑚+(1,0) = 𝑓(1,0)𝑢(2,0) + 𝑓(0,1)𝑢(1,1) =
= 0 + 1 = 1 =⇒ 𝑓 (2) ∈ 𝐹𝑁 .
Шаг 2. 𝑛 = (1, 1) ∈ 𝑠(2) + ∆ = {(0, 1); (1, 1)}, 𝑎𝑢𝑥[2] = 1.
Шаг 3. Условие выполнено. 𝑓 (2) := BP⟨2, 1⟩ = 𝑥2 + 𝑥1 + 1. Переход нашаг 8.
Шаг 8. 𝑝𝑡𝑛 := (0, 2) (𝐹 = {𝑓 (1) = 𝑥21; 𝑓(2) = 𝑥2 + 𝑥1 + 1}).
VI. Шаг 1. 𝑠(1) = (2, 0) ̸6 𝑛 = (0, 2) =⇒ 𝑓 (1) ∈ 𝐹𝑉 .𝑠(2) = (0, 1) 6 𝑛 = (0, 2).
𝑓 (2)[𝑢](0,2) =∑︁
𝑓𝑚𝑢𝑚+(0,1) =
= 𝑓(0,0)𝑢(0,1) + 𝑓(1,0)𝑢(1,1) + 𝑓(0,1)𝑢(0,2) =
= 1 + 1 + 0 = 0 =⇒ 𝑓 (2) ∈ 𝐹𝑉 .
Шаг 8. 𝑛 := (3, 0).
VII. Шаг 1. 𝑠(1) = (2, 0) 6 𝑛 = (3, 0).𝑓 (1)[𝑢](3,0) =
∑︀𝑓𝑚𝑢𝑚+(1,0) = 𝑓(2,0)𝑢(3,0) = 0 =⇒ 𝑓 (1) ∈ 𝐹𝑉 .
𝑠(2) = (0, 1) ̸6 𝑛 = (3, 0) =⇒ 𝑓 (2) ∈ 𝐹𝑉 .
Шаг 8. 𝑛 := (2, 1).
23
2 Реализация
Реализация алгоритма выполнена с использованием языка программи-рования общего назначения C++ в соответствии с действующим стандар-том [18], и в совокупности с широким распространением компиляторов сэтого языка может использоваться на большом числе программно-аппа-ратных платформ. Подготовлены бинарные сборки для платформы x86-GNU/Linux (бинарный формат ELF).
При реализации использованы две библиотеки программных кодов соткрытыми исходными кодами:
∙ NTL, версия 5.4.2 [20] — содержит реализацию арифметики в конеч-ных полях;
∙ Boost, версия 1.37.0 [21] — использованы средства, повышающие удоб-ство использования STL.
Кроме того, NTL может быть опционально скомпилирована с библиоте-кой GMP (GNU Multiple Precision Arithmetic Library [22]) для повышенияпроизводительности, что и было сделано в данном случае (версия GMP4.2.2). Использованные в работе библиотеки либо проверены временем —разработка NTL относится к началу 90-х и с тех пор стабильно поддержи-вается, — либо имеют мощное сообщество пользователей и разработчиков,куда входят, в частности, профессионалы, ответственные за развитие языкаC++ (Boost).
Реализация спроектирована в объектно-ориентированном стиле с широ-ким применением STL, которая вносит элементы аппликативного програм-мирования. Работу по реализации можно разделить на три части:
1. Арифметический процессор: полиномы от двух переменных, двумер-ные последовательности, точки дискретной плоcкости (с учётом диф-ференциации точек, накладываемой алгоритмом).
2. Определение контейнерных структур данных для представления со-вокупностей полиномов, которыми в разных контекстах оперирует ал-горитм.
24
3. Реализация алгоритма.
Ниже охарактеризованы основные особенности каждой из этих подсистем.
2.1 Арифметический процессор
Стоит отметить, что NTL содержит реализацию арифметики в коль-цах полиномов лишь от одной переменной; самостоятельных библиотек соткрытой реализацией полиномов двух (многих) переменных аналогично-го NTL и Boost класса найти не удалось. Был создан класс полиномов отдвух переменных, а также реализованы необходимые операции с объектамиэтого класса.
Реализация последовательно использует механизм шаблонов C++. Впервую очередь это относится к параметризации типов коэффициентов по-линома и элементов последовательности. Такое решение обусловлено несколь-кими причинами. Одна из них — дизайн NTL, в которой конечные поляразличных типов (простые, расширенные, характеристики 2) представленысовокупностью не связанных между собой какими-либо языковыми сред-ствами классов. В такой ситуации обеспечение полиморфизма создаваемогокода не может осуществляться при помощи традиционных для объектно-ориентированного программирования механизмов наследования и вирту-альных функций. С другой стороны, шаблоны хорошо показывают себя приработе с набором классов, реализующих некоторый «неявный интерфейс»(случай NTL), обеспечивая параметрический полиморфизм [23].
Удобство использования шаблонов C++ совместно с классами NTL от-части может быть обусловлено тем, что библиотека во многих моментахполагается на механизм макросов (это остаётся, однако, практически незаметным для её пользователя): шаблоны создавались, в том числе, какзамена небезопасным в использовании макросам и, решая аналогичные за-дачи, шаблоны — быть может, против воли создателей — достаточно хорошосочетаются с макросами.
Вторая причина попытки создать код, абстрагированный от типов кон-кретных алгебраических структур, состоит в том, что исходный алгоритм
25
Берлекэмпа—Месси находит всё новые интерпретация, расширения и обоб-щения. В том числе, рассматривались варианты алгоритма над различны-ми типами колец и модулями [12, 13], кроме того, в более поздних, чемосновная [14] для данной реализации, работах Сакаты изучалась задачапостроения группы полиномов с предписанными нулями в предположении,что нули лежат в некотором расширении поля коэффициентов многочле-нов [25]. В этой ситуации одной из задач стало создание максимально гиб-кой реализации основных модулей программы для облегчения дальнейшегоизучения алгоритма и его приложений.
Как и в случае классического алгоритма Берлекэмпа—Месси, в расчё-тах не используется умножение двух полиномов общего вида, а — толькоумножение полинома на моном, что делает разумным отдельную реализа-цию этой операции, которая работает более эффективно, чем умножение вобщем случае.
Из других особенностей реализации подсистемы арифметического про-цессора можно указать решение, связанное с операцией 𝑓 [𝑢]𝑛. Здесь ис-пользован паттерн проектирования, известный под именем Прокси-класс(или Заместитель) [24]. Одной из задач реализации была удобочитаемостькода, в обеспечении которой большую роль играет перегрузка операцийC++. В данном случае была перегружена операция обращения по индек-су (subscript operator) класса полинома. Однако, эта операция не можетбыть сделана тернарной (что позволило бы легко приблизить её вызов кматематической записи). В таких случаях можно воспользоваться допол-нительным классом (обычно его называют прокси-класс), который сохра-няет информацию, переданную бинарной операции обращения по индексу,то есть «запоминает» ссылки на полином и последовательность, и для кото-рого определена перегруженная операция вызова функции (call operator),принимающая объект-точку дискретной плоскости. Последняя выполняетнеобходимые вычисления, а в коде это выглядит так: f[u](n). Важным яв-ляется тот факт, что прокси-класс является деталью реализации, котораяостаётся максимально скрытой для клиента класса полинома.
26
2.2 Контейнерные структуры данных
В ходе выполнения алгоритма конструируются и изменяются ряд мно-жеств. Было выделено три типа данных:
∙ PolySet для хранения текущего минимального множества.
∙ PolyWithAuxInfo для хранения «вспомогательного» (auxiliary) мно-жества 𝐺.
∙ PolySubset для хранения подмножеств минимального множества 𝐹𝑉
и 𝐹𝑁 .
Первые два основаны на стандартном типе множества C++ std::set иопределяют несколько дополнительных операций, используемых в алгорит-ме. Выбор std::set обусловлен необходимостью поддерживать указанныемножества в порядке, таком что старшие степени образуют гиперболиче-ский набор: здесь используется особенность типа множества C++, которое вдействительности является упорядоченным множеством. Пример добавлен-ной операций доставляет добавленная в PolySet проверка того, что даннаяточка находится в сдвинутом в данную точку ∆-множестве, определяемомданным минимальным множеством полиномов (т. е. объектом PolySet).Кроме того, в обоих типах присутствует операция обращения по индексудля того, чтобы код, реализующий процедуру Берлекэмпа, наиболее выра-зительно отражал математическую запись.
PolyWithAuxInfo является множеством, хранящим тройки: полином,точка дискретной плоскости и элемент поля (упакованные в структуруC++), — сочетая в себе, таким образом, три множества из описания ал-горитма: 𝐺, 𝑃𝐺, 𝐷𝐺. Множества старших степеней для 𝐹 и 𝐺, то есть𝑆 и 𝑇 , также не хранятся отдельно: степень является полем класса поли-нома, и потому информация из 𝑆 и 𝑇 содержится в объектах PolySet иPolyWithAuxInfo соответственно.
Третий контейнерный тип PolySubset реализован как стандартный спи-сок (std::list) структур, содержащих пары: итератор, указывающий наполином в текущем минимальном множестве, и индекс этого полинома.
27
Таким образом, для хранения полиномов в подмножествах исключено до-полнительное копирование. Это можно считать вариантом паттерна При-способленец (Flyweight) [24]. Здесь сыграли роль не только соображенияэффективности, но и особенности алгоритма: рассматривая полином в под-множестве нужно иметь возможность модифицировать его либо удалять —так, чтобы эти изменения отразились на самом минимальном множестве.
Стоит отметить, что простое (отдельно стоящее) определение псевдо-нима типа (typedef) списка структур для случая PolySubset выполнитьнельзя, потому что тип итератора по множеству полиномов зависит от шаб-лонных параметров полинома, тогда возможное определение псевдонимабыло бы шаблонным, что запрещено текущим стандартом C++. Эта слож-ность известная под названием template typedefs будет снята в следующемстандарте C++, где определения «шаблонных псевдонимов» будут разре-шены [19].
2.3 Реализация алгоритма
Весь алгоритм был оформлен в виде отдельного класса. Объектно-ори-ентированный подход к построению реализации алгоритма позволил про-извести достаточно глубокую декомпозицию, чтобы отразить основные ша-ги алгоритма. Были выделены основные фазы алгоритма, код выполнениякоторых помещался в отдельные методы. Определены, во-первых, данные,используемые и последовательно изменяемые несколькими фазами, а зна-чит, подлежавшие оформлению в виде полей класса, и, во-вторых, данные,являющиеся локальными для каждого шага или даже его части. Таким об-разом, принятые в ходе проектирования решения помогают глубже понятьприроду и особенности алгоритма.
Известно, что объектно-ориентированный подход позволяет последова-тельно строить сколько угодно сложные абстракции, равномерно распре-деляя общую сложность между различными уровнями абстракции. Дваописанных выше программных модуля содержали более низкоуровневыеобъекты и операции. Реализация же самого алгоритма в сравнении с ними
28
представляется более высокоуровневой. Поясним этот тезис.Класс алгоритма Algorithm содержит единственный публичный метод
computeMinimalSet для получения минимального множества по заданнойв конструкторе последовательности, и приведённая в разделе 1.3 схема ал-горитма практически дословно отображается на тело цикла этого метода:
buildFNandFV ( ) ; // шаг 1i f (FN. empty ( ) ) { // goto на шаге 3
continue ;}// в условии ниже: шаг 2 и if из шага 3// параметр degreeInvariantSuppliers — множество auxi f ( i sAtTheDegreeInvar iantPoint ( d eg r e e Inva r i an tSupp l i e r s ) ) {
renewF ( deg r e e Inva r i an tSupp l i e r s ) ; // then из шага 3} else {
buildNewDeltaSet ( ) ; // шаг 4PolySet<T, S> F_new = buildNewF ( ) ; // шаг 5buildNewG(F_new) ; // шаг 6F = F_new;
}
Таким образом, за самым верхним уровнем абстракции, когда мы про-сто получаем решение (клиентский код, вызывающий computeMinimalSet),сразу идёт уровень, решающий задачу в терминах схемы алгоритма (телоcomputeMinimalSet). Далее, как видно из приведённого кода, сложностьраспределена по методам класса Algorithm. Общее количество этих мето-дов около пятнадцати штук, но основные из них уже видны выше. Большаячасть этих методов имеет довольно лаконичное тело, так как они, в своюочередь, полагаются на более низкие уровни абстракции, описанные, в томчисле, в разделах 2.1 и 2.2.
Исходные коды реализации приведены в приложении.
29
3 Применение BMS-алгоритма для декодиро-вания АГ-кодов типа кодов Рида—Соломо-на
3.1 АГ-коды типа кодов Рида—Соломона
Рассмотрим конструкцию семейства кодов [17], которые иногда назы-вают алгебро-геометрическими кодами типа кодов Рида—Соломона. Пустьзадано конечное поле F𝑞 из 𝑞 элементов, полином 𝐶(𝑥, 𝑦) ∈ F𝑞[𝑥, 𝑦]. Мно-жество точек (𝑥, 𝑦), координаты 𝑥 и 𝑦 которых лежат в алгебраическомзамыкании F поля F𝑞, таких что 𝐶(𝑥, 𝑦) = 0 называется афинной кривой,а сами точки — точками афинной кривой 𝐶(𝑥, 𝑦). Точка афинной кривойназывается рациональной, если обе её координаты принадлежат F𝑞.
Для удобства расчёта параметров строящегося семейства кодов на кри-вую накладывают дополнительные ограничения. Полной степенью поли-нома 𝑓 от любого конечного числа 𝑠 переменных {𝑥𝑖}𝑠𝑖=1 назовём макси-мальную сумму степеней переменных в терме (члене) 𝑓 :
𝑓 =∑︁𝛼∈N𝑠
0
𝑓𝛼𝑥𝛼 : deg 𝑓
def= max
𝑓𝛼 ̸=0
∑︁𝑖
𝛼𝑖.
Определение корректно, так как лишь конечное число 𝑓𝛼 отличны от нуля.Для полинома 𝑓 ∈ F𝑞[𝑥1, . . . , 𝑥𝑠] определим операцию гомогенизации [26]
𝑓 ↦→ 𝑓ℎ, 𝑓ℎ ∈ F𝑞[𝑥0, . . . , 𝑥𝑠]:
𝑓ℎ(𝑥0, 𝑥1, . . . , 𝑥𝑠)def= 𝑥deg 𝑓0 𝑓
(︂𝑥1𝑥0
, . . . ,𝑥𝑠𝑥0
)︂.
Таким образом, число переменных полинома увеличивается на одну, и онстановится однородным, то есть суммарные степени переменных в каждомтерме совпадают (и равны deg 𝑓).
Важное свойство однородных полиномов состоит в том, что для любо-го корня 𝑃 ∈ F𝑠
𝑞 однородного полинома, 𝜆𝑃 , где 𝜆 ∈ F𝑞, также является
30
его корнем. Далее, говоря о корне однородного полинома, будет подразуме-ваться корень с точностью до множителя 𝜆.
Можно определить вложение F𝑠 →˓ F𝑠+1, при котором все корни исход-ного полинома 𝑓 станут корнями 𝑓ℎ (нужно положить новую координатуравной 1, оставив неизменными старые). Конечно, у 𝑓ℎ могут появитьсяи другие корни. Используя геометрический язык, говорят, что кривая 𝑓ℎ
является проективным замыканием кривой 𝑓 [26].Определим формальную частную производную полинома 𝑓 ∈ F𝑞[𝑥1, . . . , 𝑥𝑠]
по переменной 𝑥𝑖: 𝑓 ↦→ 𝑓𝑥𝑖, 𝑓𝑥𝑖
∈ F𝑞[𝑥1, . . . , 𝑥𝑠],
𝑓 =∑︁𝛼∈N𝑠
0
𝑓𝛼𝑥𝛼 : 𝑓𝑥𝑖
def=
∑︁𝑓𝛼 ̸=0𝛼𝑖>0
𝛼𝑖𝑓𝛼𝑥𝛼−𝑒𝑖,
где запись 𝛼𝑖𝑓𝛼 означает∑︀𝛼𝑖
𝑘=1 𝑓𝛼, а вектор 𝑒𝑖 ∈ N𝑠0 имеет все нулевые ко-
ординаты, за исключением 𝑖-ой, которая равна 1.Точка 𝑃 кривой 𝑓 называется особой (сингулярной), если все формаль-
ные частные производные в ней равны нулю. В противном случае точканазывается неособой (гладкой). Кривая называется регулярной, если её про-ективное замыкание не имеет особых точек.
Ограничение, о котором упоминалось выше, состоит в том, что для по-строения рассматриваемого семейства кодов используются регулярные кри-вые 𝐶(𝑥, 𝑦).
Будем считать, что на парах целых неотрицательных чисел Σ0 = N20
(а значит, на множестве мономов из F𝑞[𝑥, 𝑦]) введён линейный порядок <T
(см. раздел 1.2). Пусть 𝐶(𝑥, 𝑦) = 0 — уравнение регулярной кривой степени𝑚 (то есть старшая относительно <T степень многочлена 𝐶(𝑥, 𝑦) равна 𝑚),а {𝑃𝑖 = (𝑥𝑖, 𝑦𝑖)}𝑛𝑖=1 — рациональные точки на ней. Выберем целое 𝑗, такое,что
𝑚− 2 6 𝑗 6
⌊︂𝑛− 1
𝑚
⌋︂.
Мономы из множества {𝑥𝑎𝑦𝑏 | (𝑎, 𝑏) 6T (0, 𝑗)} перенумеруем так: {𝜙𝑖}𝜇𝑖=0,где 𝜇 = 𝜇(𝑗) — более точно, эта нумерация определяется биективным отоб-
31
ражением(𝑎, 𝑏) ↦→ ((𝑎 + 𝑏)2 + 𝑎 + 3𝑏)/2. (8)
Код типа Рида—Соломона 𝐶*(𝑗) задаётся проверочной матрицей H:
H =
⎡⎢⎢⎢⎢⎣𝜙0(𝑃1) . . . 𝜙0(𝑃𝑛)
𝜙1(𝑃1) . . . 𝜙1(𝑃𝑛)... ...
𝜙𝜇(𝑃1) . . . 𝜙𝜇(𝑃𝑛)
⎤⎥⎥⎥⎥⎦ (9)
Пусть 𝑘 это размерность данного кода, а 𝑑𝑚𝑖𝑛 — его минимальное расстоя-ние. Можно доказать [16], что:
𝑘 = 𝑛− (𝑚𝑗 − 𝑔 + 1),
𝑑𝑚𝑖𝑛 ≥ 𝑑* = 𝑚𝑗 − 2𝑔 + 2,
где 𝑔 это параметр, называемый родом кривой. В случае регулярной кривойстепени 𝑚
𝑔 = (𝑚− 1)(𝑚− 2)/2.
Величина 𝑑* называется конструктивным кодовым расстоянием.
3.2 Метод декодирования АГ-кодов типа кодов Рида—
Соломона Юстесена—Ларсена—Йенсена—Хохоль-
да
Ниже будет изложен метод декодирования, первоначально описанныйв [17].
Пусть по каналу пришло слово r ∈ F𝑛𝑞 , и r = c + e, где c это кодовое
слово, а e — вектор ошибок, возникших при передаче. Задача декодера —определить вектор ошибок e [17, раздел IV].
Синдром s ∈ F𝜇𝑞 определяется так:
s = Hr𝜏 = He𝜏 .
32
Предположим, что ошибки произошла в позициях, отвечающих точкам(𝑥𝑖, 𝑦𝑖), 𝑖 ∈ 𝐼 ⊂ {1, . . . , 𝑛}. Обозначим
𝑆𝑎𝑏 =∑︁𝑖∈𝐼
𝑒𝑖𝑥𝑎𝑖 𝑦
𝑏𝑖 , (𝑎, 𝑏) 6T (0, 𝑗). (10)
Неизвестными являются, как позиции ошибок (𝑥𝑖, 𝑦𝑖), так и их величины𝑒𝑖. Как и в классическом декодере Питерсона—Горенстейна—Цирлера [15]для кодов Рида—Соломона, эти две проблемы решаются отдельно. Перваясвязана с введением полинома локаторов ошибок :
𝜎(𝑥, 𝑦) =∑︁𝑙,𝑘
𝜎𝑙𝑘𝑥𝑙𝑦𝑘,
который по определению содержит среди своих корней {𝑃𝑖}𝑖∈𝐼 и не делитсяна 𝐶(𝑥, 𝑦).
Полином локаторов ошибок обладает одним важным свойством. Рас-смотрим выражение
∑︀𝑙,𝑘 𝜎𝑙𝑘𝑆𝑎+𝑙,𝑏+𝑘:∑︁
𝑙,𝑘
𝜎𝑙𝑘𝑆𝑎+𝑙,𝑏+𝑘 =∑︁𝑙,𝑘
𝜎𝑙𝑘∑︁𝑖∈𝐼
𝑒𝑖𝑥𝑎+𝑙𝑖 𝑦𝑏+𝑘
𝑖 =
=∑︁𝑖∈𝐼
𝑒𝑖𝑥𝑎𝑖 𝑦
𝑏𝑖
∑︁𝑙+𝑘6ℎ
𝜎𝑙𝑘𝑥𝑎𝑙 𝑦
𝑘𝑖 = 0. (11)
Здесь 𝑎 и 𝑏 берутся такими, что (𝑎+ 𝑙, 𝑏+𝑘) 6T (0, 𝑗), то есть 𝑆𝑎+𝑙,𝑏+𝑘 имеетсмысл. Последнее равенство выполняется, потому что внутренняя суммасодержит полином 𝜎, вычисленный в своих корнях 𝑃𝑖 = (𝑥𝑖, 𝑦𝑖).
Соотношения (11) должны быть поданы на вход BMS-алгоритму. Мно-гочлен минимальной степени из минимального множества, полученного поBMS-алгоритму, будет многочленом локаторов ошибок, если количествоошибок в канале 𝑡 удовлетворяет неравенству [17, Теорема 4]:
𝑡 < 𝑑*/2 −𝑚2/8 + 𝑚/4 − 1/8. (12)
После нахождения 𝜎, нужно определить его корни из числа {𝑃𝑖}, под-
33
ставить их в (10) и решить её относительно вектора ошибок e одним изобщих методов решения систем линейных уравнений.
В заключение сделаем замечание о границе для числа исправляемыхошибок (12). Она более ограничительна, чем привычное для классических(не алгебро-геометрических) помехоусточивых кодов, 𝑡 < 𝑑*/2. Оказыва-ется, в случае АГ-кодов также можно исправлять ошибки до половиныконструктивного кодового расстояния 𝑑*. Это было доказано Фенгом иРао [27].Применение их техники «голосования большинством» (majorityvoting) к рассматриваемым кодам можно найти в [28]. Основная идея со-стоит в нахождении дополнительных синдромов (для получения большегочисла уравнений (11)), используя уравнение кривой и информацию из BMS-алгоритма на промежуточных шагах. Как ясно, это требует более тонкоговстраивания BMS-алгоритма в схему декодирования.
34
3.3 Схема алгоритма декодирования
Вход: пришедшее по каналу слово r
Вычислить синдром:s = Hr𝜏
Переупорядочитьего компоненты: 𝑆𝑎𝑏
BMS-алгоритмВход: {𝑆𝑎𝑏}Выход: минимальноемножество 𝐹
Для элемента 𝐹 минимальной степенинайти его корни среди {(𝑥𝑖, 𝑦𝑖)}
Вычислить e из системы:𝑆𝑎𝑏 =
∑︀𝑒𝑖𝑥
𝑎𝑖 𝑦
𝑏𝑖
Выход: e
Переупорядочение в первом блоке производится с помощью отображе-ния (8).
35
Заключение
В данной работе построена схема BMS-алгоритма, которая может слу-жить руководством для независимых реализаций. Выполнена реализацияBMS-алгоритма на языке программирования C++. Рассмотрена возмож-ность применения алгоритма для декодирования алгебро-геометрическихкодов типа кодов Рида—Соломона.
Дальнейшая работа может быть проведена по нескольким направлени-ям. Интерес представляет реализация построенной в разделе 3.3 схемы де-кодера. Кроме того, как отмечено в разделе 3.2, схема может быть услож-нена для повышения числа исправляемых декодером ошибок за счёт болеесложного встраивания BMS-алгоритма в декодер.
Имеются работы, обсуждающие 𝑛-мерную версию BMS-алгоритма [25](мы рассмотрели двумерную версию), которая также может стать предме-том дальнейшей разработки и реализации. Использование её при декодиро-вании кодов на кривых высших размерностей также может быть проведено,однако трудность практического применения такого кодека заключается вотсутствии явных конструкций многомерных кривых с достаточно богатымзапасом рациональных точек [17].
36
Список литературы
[1] Шеннон К. Математическая теория связи. – В сб. «Работы по теорииинформации и кибернетике». М., Иностранная литература, 1963.
[2] Goppa V. D., Codes associated with divisors // Prohl. Peredach, Inform.1977. Vol. 13. No. 1. Pp. 33-39,
[3] Tsfasman M. A., Vladut S. G., Zink T., Modular curves, Shimura curvesand Goppa codes, better than Varshamov—Gilbert bound // Math. Nuchr.1982. Vol. 104. Pp. 13–28.
[4] Алфёров А. П., Зубов А. Ю., Кузьмин А. С., Черёмушкин А. В. Основыкриптографии: учебное пособие. — М.: Гелиос АРВ. 2005.
[5] O’Sullivan M. New codes for the Berlekamp-Massey-Sakata algorithm //Finite Fields Appl. 2001. No 7. Pp. 293–317.
[6] Пеленицын А.М. О реализации декодера одного класса алгебро-геометрических кодов с использованием алгоритма Сакаты // Неделянауки 2008: сб. тезисов. Том 1. — Ростов н/Д: Изд-во ЮФУ. 2008. С.55–57.
[7] Маевский А.Э., Пеленицын А.М. О программной реализации алгебро-геометрического кодека с применением алгоритма Сакаты // В сб.«Материалы X Международной научно-практической конференции„Информационная безопасность“», ч.2. Таганрог. ЮФУ. 2008. С. 55–57.
[8] Маевский А.Э., Пеленицын А.М. Реализация программного алгебро-геометрического кодека с применением алгоритма Сакаты // Изв.ЮФУ. Технические науки. 2008. №8. С. 196–198.
[9] Berlekamp E. R. Algebraic Coding Theory – New York: McGrow Hill,1968. (Перевод: Берлекэмп Э. Алгебраическая теория кодирования. –М.: Мир, 1971.)
37
[10] Massey J.L., Shift Register Synthesis and BCH Decoding, // IEEE Trans.Inform. Theory. 1969, Vol. IT-15. No. 1.
[11] Gashkov S.B., Gashkov I.B. The Berlekamp-Massey Algorithm. A Sightfrom Theory of Pade Approximants and Orthogonal Polynomials // LNCS.2004. Vol. 3037. Pp. 561–564.
[12] Kurakin V.L., Kuzmin A.S., Mikhalev A.V., Nechaev A.A. Linear recurringsequences over rings and modules // I. of Math. Science. ContemporaryMath. and it’s Appl. Thematic surveys. 1994. Vol. 10. I. of Math. Sciences.1995. Vol. 76. № 6.
[13] Куракин В.Л. Алгоритм Берлекэмпа—Месси над коммутативными ар-тиновыми кольцами главных идеалов // Фундаментальная и приклад-ная математика. 1999. Том 5. Вып. 4.
[14] Sakata S. Finding a minimal set of linear recurring relations capable ofgenerating a given finite two–dimensional array // J. Symb. Comp. 1988.Vol. 5. Pp. 321–337.
[15] Блейхут Р. Теория и практика кодов, контролирующих ошибки — М.:Мир, 1986.
[16] Justesen J., Larsen K.J., Havemose A., Jensen H.E., and Høholdt T.Construction and Decoding of a Class of Algebraic Geometry Codes //IEEE Trans. Inform. Theory. 1989. Vol. 35, Pp. 811–821.
[17] Justesen J., Larsen K.J., Jensen H. E., and Høholdt T. Fast decoding ofcodes from algebraic plane curves // IEEE Trans. Inform. Theory. 1992.Vol. 38. Pp. 111-119.
[18] ISO Information Technology — Programming Languages — C++Document Number ISO/IEC 14882-1998 ISO/IEC, 1998.
[19] Working Draft, Standard for Programming Language C++, 2009-03-23(Черновик стандарта C++).
38
[20] NTL: A Library for doing Number Theory by Victor Shoup, веб-сайт:http://shoup.net/ntl/
[21] Boost: C++ Libraries, веб-сайт: http://www.boost.org/
[22] GNU Multiple Precision Arithmetic Library, веб-сайт: http://gmplib.org/
[23] Вандевурд Д., Джосаттис Н. Шаблоны С++: справочник разработчи-ка. — М.: Издательский дом «Вильямс», 2003.
[24] Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж. Приёмы объект-но-ориентированного проектирования. Паттерны проектирования. —СПб.: Питер, 2001.
[25] Sakata S. N-dimensional Berlekamp-Massey algorithm for multiple arraysand construction of multivariate polynomials with preassigned zeros //LNCS. Vol. 357. 1989. Pp. 356–376.
[26] Кокс Д., Литтл Дж., О’Ши Д. Идеалы, многообразия и алгоритмы.Введение в вычислительные аспекты алгебраической геометрии и ком-мутативной алгебры. — М.: Мир, 2000.
[27] Feng G. L., Rao T. R. N., Decoding algebraic-geometric codes up to thedesigned minimum distance // IEEE Trans. Inform. Theory. 1993. Vol. 39.Pp. 37–45.
[28] Sakata S., Justesen J., Madelung Y., Jensen H. E., Høholdt T., Fastdecoding of AG-codes up to the designed minimum distance // IEEE Trans.Inform. Theory. 1993. Vol. 41. Pp. 1672–1677.
39
Приложение
Большинство классов являются шаблонными, и, в соответствии с пра-вилами C++, должны целиком помещаться в заголовочные файлы. Одна-ко для большего удобства объявления и определения объёмных шаблон-ных классов разнесены в разные файлы. При таком разделении создавалсяфайл, содержащий всего две директивы #include, включавшие текст фай-ла с объявлением и текст файла с определением членов шаблонного класса— такие вспомогательные файлы не включены в листинг.
BMSAlgorithm.h
#ifndef _BMSALGORITHM_H#define _BMSALGORITHM_H
#include <algorithm>#include <cas s e r t >#include <iostream>#include <map>#include <set>#include <u t i l i t y >#include <vector>
#include "PolySet . h"#include "Polynomial . h"#include "Sequence . h"#include "DeltaSet . h"
namespace bmsa {
using std : : vec to r ;using std : : pa i r ;using namespace boost : : lambda ;using namespace boost : : t up l e s ;
template<typename T, typename S = T> // T = Poly Coef Type// S = Seq Elem Type
40
class Algorithm {typedef std : : l i s t <Point> Po in tCo l l e c t i on ;typedef std : : l i s t <PolySubsetEntry<T, S> > PolySubset ;
Sequence<S> const & u ;
Point n ; // curren t s t ep o f the a l gor i thm
PolySet<T, S> F; // curren t minimal s e tPolyWithAuxInfoSet<T, S> G;
PolySubset FN;PolySubset FV;
vector<typename Polynomial<T, S>: : Coef> d i s c r ; // curren t// d i s c r e panc i e s
vector<size_t> deg r e e Inva r i an tSupp l i e r s ;DeltaSet newDeltaSet ;
public :Algorithm ( Sequence<S> const & u_) : u(u_) ,
F( ElemTypeTraits<typename Polynomial<T, S>: : Coef >: : id ( )) {}
PolySet<T, S> computeMinimalSet ( ) ;
private :void clearParams ( ) ;
void buildFNandFV ( ) ;
bool i sAtTheDegreeInvar iantPoint (vector<size_t> & deg r e e Inva r i an tSupp l i e r s ) ;
void renewF ( vector<size_t> const & deg r e e Inva r i an tSupp l i e r s ) ;
// Berlekamp procedurePolynomial<T, S> BP( s i ze_t i , s i z e_t j ) ;
41
// Subs i d i a ry procedure −− the con f l u en t ve r s i on o f BPtemplate <size_t K>Polynomial<T, S> SP( s i ze_t ) ;
void buildNewDeltaSet ( ) ;PolySet<T, S> buildNewF ( ) ;void buildNewG( PolySet<T, S> const &) ;bool fnBetweenFs ( Polynomial<T, S> const & f ,
Polynomial<T, S> const & fNext ,Polynomial<T, S> const & fn ) const ;
// c o n s t i t u t e s b u i l d i n g new de l t a−s e tvoid addPointsOfTypeI ( ) ;void addPointsOfTypeII ( ) ;void addPointsOfTypeIII ( ) ;void addPointsOfTypeIV ( ) ;
Del taSetPointpointOfTypeIFromPolySubsetEntry ( PolySubsetEntry<T, S> const &) ;
Polynomial<T, S>buildPolyFromDeltaSetPoint ( DeltaSetPoint const &) ;
} ;
} // namespace bmsa#endif /* _BMSALGORITHM_H */
BMSAlgorithm.cc
#include <algorithm>#include <stdexcept>#include <i t e r a t o r >#include <iostream>
#include <cstdde f> // s i z e_t
#include <boost /lambda/lambda . hpp>#include <boost /lambda/bind . hpp>#include <boost / func t i on . hpp>
42
#include "Polynomial . h"#include "PolySet . h"#include "BMSAlgorithm . h"
using std : : cout ;using std : : endl ;
namespace bmsa {
template<typename T, typename S>PolySet<T, S> Algorithm<T, S>: : computeMinimalSet ( ) {
for (n = Point : : n i l ; t o t a l L e s s (n , u . s i z e ( ) ) ; ++n ) {clearParams ( ) ;buildFNandFV ( ) ; // f i nd po lynomia l s non−v a l i d
// at the curren t s t epi f (FN. empty ( ) ) {
cout << "F_N i s empty − F would not change" << endl ;continue ;
}i f ( // n i s in the degree−i n va r i an t s e t f o r each f in FN
i sAtTheDegreeInvar iantPoint (d eg r e e Inva r i an tSupp l i e r s ) ) {
cout << "Delta−s e t would not change" << endl ;// de l t a−s e t and s i z e o f F unchangedrenewF ( deg r e e Inva r i an tSupp l i e r s ) ;s td : : cout << "F renewed : \ n\ t " << F << std : : endl ;
} else {buildNewDeltaSet ( ) ;cout << "New del ta−s e t : "<< endl << "\ t " <<
newDeltaSet ;PolySet<T, S> F_new = buildNewF ( ) ;buildNewG(F_new) ;F = F_new;
}}return F;
}
43
template<typename T, typename S>void Algorithm<T, S>: : c learParams ( ) {
FN. c l e a r ( ) ;FV. c l e a r ( ) ;d e g r e e Inva r i an tSupp l i e r s . c l e a r ( ) ;d e g r e e Inva r i an tSupp l i e r s . r e s i z e (F . s i z e ( ) ) ;d i s c r . c l e a r ( ) ;newDeltaSet . c l e a r ( ) ;
}
template<typename T, typename S>void Algorithm<T, S>: : buildFNandFV ( ) {
s i ze_t i = 0 ;for (
typename PolySet<T, S>: : c on s t_ i t e r a to r f I t = F . begin ( ) ;f I t != F . end ( ) ;++f I t , ++i ) {
typename Polynomial<T, S>: : Coef d ; // curren t d i screpancy ;// f o r f in F: i f f [ u ] ( n) cou ld be eva l ua t ed . . .// . . and d i screpancy not n u l l then// f i s non−v a l i d ( goes to FN)i f ( f I t−>getDegree ( ) <= n
&& (d = (* f I t ) [ u ] ( n) ) != typename Polynomial<T, S>: : Coef ( ) ) {
d i s c r . push_back (d) ;FN. push_back ( PolySubsetEntry<T, S>(i , f I t ) ) ;
}else {
d i s c r . push_back (typename Polynomial<T, S>: : Coef ( ) ) ;FV. push_back ( PolySubsetEntry<T, S>(i , f I t ) ) ;
}}
}
// t e s t wether n i s degree−i n va r i an t po in t f o r a l l f in FN;// i f yes , d e g r e e In va r i an tSupp l i e r s ho l d s i n d i c e s o f aux po ly ’ s// which he l p to pre s e rve the degree in the Berlekamp−procedure ;// t h i s i n f o shou ld be used in such a way ( pseudocode ) :// f o r f in FN:
44
// f = BP<f , d e g r e e In va r i an tSupp l i e r s [ indexOf ( f ) ]>template<typename T, typename S>bool Algorithm<T, S>: : i sAtTheDegreeInvar iantPoint (
vector<size_t> & deg r e e Inva r i an tSupp l i e r s ) {bool r e s u l t = true ;for (typename PolySubset : : c on s t_ i t e r a to r i t = FN. begin ( ) ;
i t != FN. end ( ) ; ++i t ) {s i ze_t degInv
= F. i s I nSh i f t e dDe l t aS e t (n , i t−>polyI t−>getDegree ( )) ;
r e s u l t = ! ( degInv == PolySet<T, S>: :NOT_IN_SHIFTED_DELTA_SET) ;
d eg r e e Inva r i an tSupp l i e r s [ i t−>polyIndex ] = degInv ;}return r e s u l t ;
}
template<typename T, typename S>void Algorithm<T, S>: : renewF ( vector<size_t> const &
deg r e e Inva r i an tSupp l i e r s ) {for (typename PolySubset : : c on s t_ i t e r a to r i t = FN. begin ( ) ;
i t != FN. end ( ) ; ++i t ) {s i ze_t nonval idPolyIdx = i t−>polyIndex ;F . r ep l a c e ( i t−>polyI t , BP( nonval idPolyIdx ,
d eg r e e Inva r i an tSupp l i e r s [ nonval idPolyIdx ] ) ) ;}
}
template<typename T, typename S>void Algorithm<T, S>: : buildNewDeltaSet ( ) {
addPointsOfTypeI ( ) ;addPointsOfTypeII ( ) ;addPointsOfTypeIII ( ) ;addPointsOfTypeIV ( ) ;
}
// though po l y s from FV g i v e po in t s o f type I ,// they are not added to de l t a−s e t// ( due to some t e c hn i c a l reasons a r i s e in b u i l d i n g F_new
45
// from t h i s d e l t s−s e t and p o s s i b l e improoved e f f i c i e n c y ) ;// buildNewF () ( b u i l d s F_new) take t h i s i n t o account ;template<typename T, typename S>void Algorithm<T, S>: : addPointsOfTypeI ( ) {
for (typename PolySubset : : c on s t_ i t e r a to r i t = FN. begin ( ) ; i t!= FN. end ( ) ; ++i t )
i f ( d eg r e e Inva r i an tSupp l i e r s [ i t−>polyIndex ]!= PolySet<T, S>: :NOT_IN_SHIFTED_DELTA_SET)
newDeltaSet . push_back (DeltaSetPoint ( DeltaSetPoint : : I , i t−>polyIndex ,
d eg r e e Inva r i an tSupp l i e r s [ i t−>polyIndex] ) ) ;
}
template<typename T, typename S>DeltaSetPointAlgorithm<T, S>: : pointOfTypeIFromPolySubsetEntry ( PolySubsetEntry<T,
S> const & psentry ) {return DeltaSetPoint ( DeltaSetPoint : : I , psentry . polyIndex ,
d eg r e e Inva r i an tSupp l i e r s [ psentry . polyIndex ] ) ;}
template<typename T, typename S>void Algorithm<T, S>: : addPointsOfTypeII ( ) {
typename PolySubset : : i t e r a t o r i t = std : : adjacent_f ind (FN. begin( ) , FN. end ( ) ,
ad jacentPo ly Ind ic i e sForPo lySubset<T, S>) ;while ( i t != FN. end ( ) ) {
newDeltaSet . push_back (DeltaSetPoint ( DeltaSetPoint : : I I , i t−>polyIndex ,
i t−>polyIndex )) ;i t = std : : adjacent_f ind(++i t , FN. end ( ) ,
ad jacentPo ly Ind ic i e sForPo lySubset<T, S>) ;}
}
template<typename T, typename S>void Algorithm<T, S>: : addPointsOfTypeIII ( ) {
46
using namespace boost : : lambda ;for (typename PolySubset : : c on s t_ i t e r a to r j I t = FN. begin ( ) ; j I t
!= FN. end ( ) ; ++j I t ) {const Point s_j = j I t−>polyI t−>getDegree ( ) ;for (typename PolySet<T, S>: : r e v e r s e_ i t e r a t o r k I t = F.
rbeg in ( ) ; k I t != F . rend ( ) ; ++kI t )i f ( n [ 1 ] >= s_j [ 1 ] + kIt−>getDegree ( ) [ 1 ] ) {
i f (n [ 0 ] >= s_j [ 0 ] + kIt−>getDegree ( ) [ 0 ] ) {typename PolySubset : : c on s t_ i t e r a to r i I t
= std : : f i nd_ i f (FN. begin ( ) , FN. end ( ) ,bind (
polyItWithPolySubsetEntryComparator<T, S>, −−kI t . base ( ) , _1) ) ;
i f ( i I t != FN. end ( ) )newDeltaSet . push_back ( DeltaSetPoint (
DeltaSetPoint : : I I I ,i I t −>polyIndex , j I t−>polyIndex ) ) ;
elsebreak ;
}else
break ;}
}}
template<typename T, typename S>void Algorithm<T, S>: : addPointsOfTypeIV ( ) {
using namespace boost : : lambda ;for (typename PolySubset : : c on s t_ i t e r a to r j I t = FN. begin ( ) ; j I t
!= FN. end ( ) ; ++j I t ) {const Point s_j = j I t−>polyI t−>getDegree ( ) ;for (typename PolySet<T, S>: : c on s t_ i t e r a to r k I t = F. begin ( )
; k I t != F . end ( ) ; ++kI t )i f ( n [ 0 ] >= s_j [ 0 ] + kIt−>getDegree ( ) [ 0 ] ) {
i f (n [ 1 ] >= s_j [ 1 ] + kIt−>getDegree ( ) [ 1 ] ) {typename PolySubset : : c on s t_ i t e r a to r i I t
= std : : f i nd_ i f (FN. begin ( ) , FN. end ( ) ,
47
bind (polyItWithPolySubsetEntryComparator<T, S>, kIt , _1) ) ;
i f ( i I t != FN. end ( ) )newDeltaSet . push_back ( DeltaSetPoint (
DeltaSetPoint : : IV ,i I t −>polyIndex , j I t−>polyIndex ) ) ;
elsebreak ;
}else
break ;}
}}
template<typename T, typename S>Polynomial<T, S> Algorithm<T, S>: : bui ldPolyFromDeltaSetPoint (
DeltaSetPoint const& pt ) {std : : cout << "DSPoint : " << pt ;Polynomial<T, S> re s ;s i z e_t k ;Point t ;switch ( pt . pointType ) {
case DeltaSetPoint : : I :r e s = BP( pt . i , pt . j ) ; break ;
case DeltaSetPoint : : I I :t = Point (n [ 0 ] − F[ pt . i ] . getDegree ( ) [ 0 ] + 1 ,
n [ 1 ] − F[ pt . j ] . getDegree ( ) [ 1 ] + 1) ;k = findPolyWithLessDegIdxInPolySubset<T, S>(FN, t ) ;r e s = BP(k , pt . i ) ; break ;
case DeltaSetPoint : : I I I :i f ( pt . i != F . s i z e ( ) − 1)
r e s = BP( pt . j , pt . i ) ;else
r e s = SP<0>(pt . j ) ;break ;
case DeltaSetPoint : : IV :i f ( pt . j != 0)
48
r e s = BP( pt . i , pt . j − 1) ;else
r e s = SP<1>(pt . i ) ;break ;
default : s td : : l o g i c_e r r o r ( " I l l e g a l type o f po int in de l ta−s e t ! " ) ;
}return r e s ;
}
template<typename T, typename S>PolySet<T, S> Algorithm<T, S>: : buildNewF ( ) {
using namespace boost : : lambda ;PolySet<T, S> re s ;add ( res , FV) ; // as po in t s from FV weren ’ t add to newDeltaSetfor ( DeltaSet : : c on s t_ i t e r a to r i t = newDeltaSet . begin ( ) ;
i t != newDeltaSet . end ( ) ; ++i t ) {Polynomial<T, S> p = buildPolyFromDeltaSetPoint (* i t ) ;r e s . i n s e r t (p) ;
}return r e s ;
}
template<typename T, typename S>bool gBetweenFs ( Polynomial<T, S> const & f , Polynomial<T, S> const &
fNext ,PolyWithAuxInfo<T, S> const & g ) {
return f . getDegree ( ) [ 0 ] == g . p [ 0 ] − g . poly . getDegree ( ) [ 0 ] + 1&& fNext . getDegree ( ) [ 1 ] == g . p [ 1 ] − g . poly . getDegree ( ) [ 1 ]
+ 1 ;}
template<typename T, typename S>bool Algorithm<T, S>: : fnBetweenFs (
Polynomial<T, S> const & f ,Polynomial<T, S> const & fNext ,Polynomial<T, S> const & fn ) const {
return f . getDegree ( ) [ 0 ] == n [ 0 ] − fn . getDegree ( ) [ 0 ] + 1&& fNext . getDegree ( ) [ 1 ] == n [ 1 ] − fn . getDegree ( ) [ 1 ] + 1 ;
49
}
template<typename T, typename S>void Algorithm<T, S>: : buildNewG( PolySet<T, S> const & F_new) {
PolyWithAuxInfoSet<T, S> GNew;for (typename PolySet<T, S>: : c on s t_ i t e r a to r f i t = F_new. begin ( )
,f i tNex t = ++F_new. begin ( ) ;f i t != −−F_new. end ( ) ; ++f i t , ++f i tNex t ) {
bool gfound = fa l se ;for (typename PolyWithAuxInfoSet<T, S>: : i t e r a t o r g i t = G.
begin ( ) ;g i t != G. end ( ) && ! gfound ;++g i t ) {
i f ( gBetweenFs (* f i t , * f i tNext , * g i t ) ) {GNew. i n s e r t (* g i t ) ;G. e r a s e ( g i t ) ; // g i t w i l l not be used any moregfound = true ;
}}i f ( gfound )
continue ;for (typename PolySubset : : i t e r a t o r f n i t = FN. begin ( ) ;
f n i t != FN. end ( ) && ! gfound ;++f n i t ) {
Polynomial<T, S> const & fnPoly = *( f n i t−>po ly I t ) ;i f ( fnBetweenFs (* f i t , * f i tNext , fnPoly ) ) {
GNew. i n s e r t ( PolyWithAuxInfo<T, S>(fnPoly , n ,fnPoly [ u ] ( n) ) ) ;
FN. e r a s e ( f n i t ) ;gfound = true ;
}}G = GNew;
}}
// Berlekamp proceduretemplate<typename T, typename S>
50
Polynomial<T, S> Algorithm<T, S>: :BP( s i ze_t i , s i z e_t j ) {a s s e r t ( 0 <= i && i < F. s i z e ( ) ) ;a s s e r t ( 0 <= j && j < G. s i z e ( ) ) ;
s td : : cout << "BP<" << i << " , " << j << ">" << endl ;Polynomial<T, S> const & f = F[ i ] ;Polynomial<T, S> const & g = G[ j ] . poly ;Point r = Point (
std : : max( f . getDegree ( ) [ 0 ] , g . getDegree ( ) [ 0 ] + n [ 0 ] − G[ j ] .p [ 0 ] ) ,
s td : : max( f . getDegree ( ) [ 1 ] , g . getDegree ( ) [ 1 ] + n [ 1 ] − G[ j ] .p [ 1 ] )
) ;Polynomial<T, S> f1 = f . onMonomialMultiply ( r − f . getDegree ( ) ) ;Polynomial<T, S> f2 = g . onMonomialMultiply ( r − n + G[ j ] . p − g .
getDegree ( ) ) ;typename Polynomial<T, S>: : Coef c = (−d i s c r [ i ] / G[ j ] . d ) ;Polynomial<T, S> re s = f1 + c * f 2 ;return r e s ;
}
template<typename T, typename S>template<size_t K>inl inePolynomial<T, S> Algorithm<T, S>: :SP( s i ze_t m) {
Point deg ;deg [K] = n [K] − F[m] . getDegree ( ) [K] + 1 ;return F[m] . onMonomialMultiply ( deg ) ;
}
} // namespace bmsa
PolySet.h
#ifndef _POLYSET_H#define _POLYSET_H
#include <algorithm>#include <iostream>
51
#include <i t e r a t o r >#include <l im i t s >#include <l i s t >#include <set>#include <stdexcept>#include <u t i l i t y >
#include <boost /lambda/bind . hpp>
#include "Polynomial . h"
namespace bmsa {
template<typename T, typename S = T>class PolySet {
typedef Polynomial<T, S> PolynomialT ;typedef std : : set<PolynomialT> Container ;
Container data ;
public :typedef typename Container : : i t e r a t o r i t e r a t o r ;typedef typename Container : : c on s t_ i t e r a to r con s t_ i t e r a to r ;typedef typename Container : : r e v e r s e_ i t e r a t o r r e v e r s e_ i t e r a t o r ;typedef typename Container : : cons t_re f e r ence cons t_re f e r ence ;typedef typename Container : : r e f e r e n c e r e f e r e n c e ;
stat ic s i ze_t NOT_IN_SHIFTED_DELTA_SET;
PolySet ( ) {}
PolySet ( PolynomialT const & p) {data . i n s e r t (p) ;
}
con s t_ i t e r a to r begin ( ) const {return data . begin ( ) ; }
con s t_ i t e r a to r end ( ) const {return data . end ( ) ; }
52
r e v e r s e_ i t e r a t o r rbeg in ( ) {return data . rbeg in ( ) ; }
r e v e r s e_ i t e r a t o r rend ( ) {return data . rend ( ) ; }
std : : pa ir<i t e r a t o r , bool>i n s e r t ( PolynomialT const & poly )
{return data . i n s e r t ( poly ) ; }
i t e r a t o r i n s e r t ( i t e r a t o r pos , PolynomialT const & poly ){return data . i n s e r t ( pos , poly ) ; }
typename Container : : s i ze_type s i z e ( ) const{return data . s i z e ( ) ; }
s i ze_t i s I nSh i f t e dDe l t aS e t ( Point const & pt , Point const &s h i f t ) ;
void r ep l a c e ( con s t_ i t e r a to r const & oldEntry ,PolynomialT const & newEntry ) ;
// 0−based po ly index in PolySetPolynomialT const & operator [ ] ( int n) const ;
} ;
template<typename T, typename S>inl inetypename PolySet<T, S>: : PolynomialT const &PolySet<T, S>: : operator [ ] ( int n) const {
con s t_ i t e r a to r i t = data . begin ( ) ;s td : : advance ( i t , n ) ;return * i t ;
}
template<typename T, typename S>inl inevoid PolySet<T, S>: : r ep l a c e ( con s t_ i t e r a to r const & oldEntry ,
Polynomial<T, S> const & newEntry ) {std : : cout << "Replac ing a poly in the PolySet : " << std : : endl
53
<< "\ to ld entry : " << *oldEntry << std : : endl ;data . e r a s e ( oldEntry ) ;s td : : cout << "\tnew entry : " << newEntry << std : : endl ;data . i n s e r t ( newEntry ) ;
}
template<typename T, typename S>inl inestd : : ostream& operator<<(std : : ostream& os , PolySet<T, S> const &
ps ) {os << "{ " ;std : : copy ( ps . begin ( ) , ps . end ( ) ,
s td : : ostream_iterator<Polynomial<T, S> >(os , " ; " ) ) ;os << "}" ;return os ;
}/***************************************************************/
template<typename T, typename S>struct PolySubsetEntry {
s i ze_t polyIndex ;typename PolySet<T, S>: : c on s t_ i t e r a to r po l y I t ;//Polynomial : : Coef d i screpancy ;
// cons t ruc t o r from f i e l d sPolySubsetEntry (
s i ze_t polyIndex_ ,typename PolySet<T, S>: : c on s t_ i t e r a to r const & polyIt_ )
:polyIndex ( polyIndex_ ) , po l y I t ( polyIt_ ) {}
} ;
template<typename T, typename S>inl inebool ad jacentPo ly Ind i c i e sForPo lySubse t (
PolySubsetEntry<T, S> const & pse1 ,PolySubsetEntry<T, S> const & pse2 ) {
return pse1 . polyIndex + 1 == pse2 . polyIndex ;}
54
template<typename T, typename S>inl inebool polyItWithPolySubsetEntryComparator (
typename PolySet<T, S>: : i t e r a t o r i t ,PolySubsetEntry<T, S> const & pse ) {
return i t == pse . po l y I t ;}
template<typename T, typename S>inl inebool greaterDegreeThenInPolySubsetEntry ( Point const & deg ,
PolySubsetEntry<T, S> const & pse ) {return pse . po ly I t−>getDegree ( ) < deg ;
}
template<typename T, typename S , typename PolySubset>inl ines i ze_t f indPolyWithLessDegIdxInPolySubset ( PolySubset const & ss ,
Point t ) {using namespace boost : : lambda ;typename PolySubset : : c on s t_ i t e r a to r i t = std : : f i nd_ i f (
s s . begin ( ) ,s s . end ( ) ,bind ( greaterDegreeThenInPolySubsetEntry<T, S>, t , _1) ) ;
i f ( i t == ss . end ( ) )throw std : : l o g i c_e r r o r ( "No poly in g iven subset which"
" degree i s l e s s then given " ) ;return i t−>polyIndex ;
}
template<typename T, typename S>inl inestd : : ostream& operator<<(std : : ostream& os , PolySubsetEntry<T, S>
const & pse ) {os << *pse . po l y I t << " idx : " << pse . polyIndex ;return os ;
}/***************************************************************/
55
template<typename T, typename S>struct PolyWithAuxInfo {
Polynomial<T, S> poly ;
Point p ; // ’ p o t e n t i a l ’ −− l a s t s t ep at which corresponding// po lynomia l had been v a l i d f o r g i ven sequence ;
typename Polynomial<T, S>: : Coef d ; // d i screpancy
PolyWithAuxInfo ( Polynomial<T, S> const & poly_ , Point const &p_,
typename Polynomial<T, S>: : Coef const & d_): poly ( poly_ ) , p(p_) , d(d_) {}
Polynomial<T, S> const * getPoly ( ) const {return &poly; }
Point const * getP ( ) const {return &p ;}} ;
template<typename T, typename S>inl inestd : : ostream& operator<<(std : : ostream& os , PolyWithAuxInfo<T, S>
const & pwai ) {os << pwai . poly << " pot : " << pwai . p << " d i s c r : " << pwai . d ;return os ;
}
template<typename T, typename S>inl inebool operator<(PolyWithAuxInfo<T, S> const & pwai1 ,
PolyWithAuxInfo<T, S> const & pwai2 ) {return pwai1 . p [ 0 ] − pwai1 . poly . getDegree ( ) [ 0 ]
> pwai2 . p [ 0 ] − pwai2 . poly . getDegree ( ) [ 0 ]&& pwai1 . p [ 1 ] − pwai1 . poly . getDegree ( ) [ 1 ]
< pwai2 . p [ 1 ] − pwai2 . poly . getDegree ( ) [ 1 ] ;}
template<typename T, typename S>class PolyWithAuxInfoSet {
56
typedef std : : set<PolyWithAuxInfo<T, S> > Container ;
Container data ;
public :typedef typename Container : : i t e r a t o r i t e r a t o r ;typedef typename Container : : c on s t_ i t e r a to r con s t_ i t e r a to r ;
c on s t_ i t e r a to r begin ( ) const {return data . begin ( ) ; }
i t e r a t o r begin ( ) {return data . begin ( ) ; }
con s t_ i t e r a to r end ( ) const {return data . end ( ) ; }
i t e r a t o r end ( ) {return data . end ( ) ; }
std : : pa ir<i t e r a t o r , bool>i n s e r t ( PolyWithAuxInfo<T, S> const & pwai )
{return data . i n s e r t ( pwai ) ; }
void e r a s e ( i t e r a t o r pos ) {return data . e r a s e ( pos ) ; }
typename Container : : s i ze_type s i z e ( ) const{return data . s i z e ( ) ; }
PolyWithAuxInfo<T, S> const & operator [ ] ( s i z e_t n) const ;} ;
template<typename T, typename S>inl inePolyWithAuxInfo<T, S> const & PolyWithAuxInfoSet<T, S>: : operator [ ] (
s i z e_t n) const {cons t_ i t e r a to r i t = data . begin ( ) ;s td : : advance ( i t , n ) ;return * i t ;
}
template<typename T, typename S>inl ine
57
std : : ostream& operator<<(std : : ostream& os ,PolyWithAuxInfoSet<T, S> const & pwaiset ) {
std : : copy ( pwaiset . begin ( ) , pwaiset . end ( ) ,s td : : ostream_iterator<PolyWithAuxInfo<T, S> >(os , " ; " )
) ;return os ;
}
template<typename T, typename S>s ize_t PolySet<T, S>: :NOT_IN_SHIFTED_DELTA_SET
= std : : numeric_limits<size_t >: :max( ) ;
// re turns the 0−based index o f F−e lement f o r which// pt i s in s h i f t e d de l t a−s e t ;// NOT_IN_SHIFTED_DELTA_SET i f n i s not in s h i f t e d de l t a−s e t// f o r any f from Ftemplate<typename T, typename S>s ize_t PolySet<T, S>: : i s I nSh i f t e dDe l t aS e t ( Point const & pt , Point
const & s h i f t ) {i f ( data . s i z e ( ) < 2)
return NOT_IN_SHIFTED_DELTA_SET; // de l t a−s e t i s emptys i ze_t f Idx = 0 ;for ( con s t_ i t e r a to r f I t = data . begin ( ) ; f I t != −−data . end ( ) ;
++f I t , ++f Idx ) {con s t_ i t e r a to r fNext I t ( f I t ) ;++fNext I t ;i f ( pt [ 0 ] < s h i f t [ 0 ] + f I t−>getDegree ( ) [ 0 ]
&& pt [ 1 ] < s h i f t [ 1 ] + fNextIt−>getDegree ( ) [ 1 ] )return f Idx ;
}return NOT_IN_SHIFTED_DELTA_SET;
}
template<typename T, typename S>Polynomial<T, S> polyFromPolySubsetEntry ( PolySubsetEntry<T, S> const
& pse ) {return *pse . po l y I t ;
}
58
template<typename T, typename S , typename PolySubset>void add ( PolySet<T, S> & ps , PolySubset const & pss ) {
std : : t rans form ( pss . begin ( ) , pss . end ( ) , s td : : i n s e r t e r ( ps , ps .begin ( ) ) ,
polyFromPolySubsetEntry<T, S>) ;}
} // namespace bmsa
Poly.h
#ifndef _POLY_H#define _POLY_H#include <algorithm>#include <deque>#include <iostream>#include <vector>
#include "ElementType . h"#include "Sequence . h"#include "Point . h"
namespace bmsa {
template <typename CoefT , typename SeqElemT = CoefT>class Polynomial {public :
typedef CoefT Coef ;typedef std : : deque<Coef> OneDimStorage ;typedef std : : deque< OneDimStorage > StorageT ;
typedef Point DegreeT ;
private :class ProxyPolySeqProduct {
Polynomial const & poly ;Sequence<SeqElemT> const & seq ;
public :
59
ProxyPolySeqProduct ( Polynomial const & poly_ ,Sequence<SeqElemT> const & seq_ ) : poly ( poly_ ) ,
seq ( seq_ ) {}
typename Polynomial : : Coef operator ( ) ( Point const & pr )const ;
} ;
friend class ProxyPolySeqProduct ;
public :Polynomial ( ) {}
Polynomial ( Coef const & c ) : c o e f s (1 ) {c o e f s [ 0 ] . push_back ( c ) ;
}
StorageT const & getCoe f s ( ) const { return c o e f s ; }
void s e tCoe f s ( StorageT const & data ) ;
DegreeT getDegree ( ) const { return degree ; }
Polynomial& operator*=(Coef const &) ;
Polynomial onMonomialMultiply ( DegreeT const & monomialDegree )const ;
Polynomial& operator+=(Polynomial const & rhs ) ;
ProxyPolySeqProduct operator [ ] ( Sequence<SeqElemT> const & seq )const ;
private :StorageT co e f s ;
DegreeT degree ;
void countDegree ( ) ;
60
} ;/**************** End o f Polynomial *********************/
template<typename T, typename S>inl inePolynomial<T, S> operator *(typename Polynomial<T, S>: : Coef const &
coef ,Polynomial<T, S> poly ) {
return poly *= coe f ;}
template<typename T, typename S>inl inePolynomial<T, S> operator *( Polynomial<T, S> poly ,
typename Polynomial<T, S>: : Coef const & coe f ) {return co e f *poly ;
}
template<typename T, typename S>inl inePolynomial<T, S> operator+(Polynomial<T, S> lhs ,
Polynomial<T, S> const & rhs ) {return l h s += rhs ;
}
template<typename T, typename S>inl ine// f o r e s t a b l i s h i n g de l t a−s e tbool operator<(Polynomial<T, S> const & lhs , Polynomial<T, S>
const & rhs ) {return l h s . getDegree ( ) [ 0 ] > rhs . getDegree ( ) [ 0 ]
&& lh s . getDegree ( ) [ 1 ] < rhs . getDegree ( ) [ 1 ] ;}
// format : [ [ a b c ] [ e f ] ] − wi tou t spaces in " ] [ "template<typename T, typename S>std : : i s t ream& operator>>(std : : i s t ream& is , Polynomial<T, S> & poly
) ;
61
template<typename T, typename S>std : : ostream& operator<<(std : : ostream& os , Polynomial<T, S> const
& poly ) ;
} // namespace bmsa
#endif /* _POLY_H */
Poly.cc
#include <algorithm>#include <cstdde f>#include <func t i ona l >#include <iostream>#include <ios>#include <i t e r a t o r >#include <numeric>#include <sstream>#include <st r ing >#include <vector>
#include <boost /lambda/lambda . hpp>#include <boost /lambda/bind . hpp>#include <boost /lambda/ algor i thm . hpp>
#include "GenericTwoDimIO . h"#include "Poly . h"
namespace bmsa {
/****************** Ari thmet ic opera t i ons ***********************/template<typename T, typename S>class OneDimAddition {
typedef int IntType ;typedef typename Polynomial<T, S>: : OneDimStorage OneDimStorage ;
public :OneDimStorage operator ( ) (
OneDimStorage const & lhs ,
62
OneDimStorage const & rhs ) {i f ( l h s . s i z e ( ) < rhs . s i z e ( ) )
return operator ( ) ( rhs , l h s ) ;OneDimStorage r e s ( l h s ) ;s td : : t rans form ( rhs . begin ( ) , rhs . end ( ) , l h s . begin ( ) ,
r e s . begin ( ) ,s td : : plus<typename Polynomial<T, S>: : Coef >() ) ;
return r e s ;}
} ;
template <typename T, typename S>Polynomial<T, S>& Polynomial<T, S>: : operator+=(Polynomial<T, S> const
& rhs ) {int l engthInFir s tDimDi f = co e f s . s i z e ( ) − rhs . c o e f s . s i z e ( ) ;i f ( l engthInFi r s tDimDi f < 0) {
typename Polynomial<T, S>: : StorageT : : c on s t_ i t e r a to r i t ( rhs .c o e f s . begin ( ) ) ;
s td : : advance ( i t , c o e f s . s i z e ( ) ) ;s td : : copy ( i t , rhs . c o e f s . end ( ) , s td : : back_inser te r ( c o e f s ) ) ;s td : : t rans form (
rhs . c o e f s . begin ( ) , i t ,c o e f s . begin ( ) ,c o e f s . begin ( ) ,OneDimAddition<T, S>()
) ;} else {
std : : t rans form (rhs . c o e f s . begin ( ) , rhs . c o e f s . end ( ) ,c o e f s . begin ( ) ,c o e f s . begin ( ) ,OneDimAddition<T, S>()
) ;}this−>countDegree ( ) ;return * this ;
}
template <typename T, typename S>
63
void oneDimOnScalarMultiply (typename Polynomial<T, S>: :OneDimStorage & data ,
typename Polynomial<T, S>: : Coef const & coe f ) {using namespace boost : : lambda ;std : : for_each ( data . begin ( ) , data . end ( ) , _1 *= coe f ) ;
}
template <typename T, typename S>Polynomial<T, S>& Polynomial<T, S>: : operator*=(
typename Polynomial<T, S>: : Coef const & coe f ) {using namespace boost : : lambda ;i f ( c o e f == typename Polynomial : : Coef ( ) ) {
c o e f s . c l e a r ( ) ;countDegree ( ) ;
} elsestd : : for_each ( c o e f s . begin ( ) , c o e f s . end ( ) ,
bind ( oneDimOnScalarMultiply<T, S>, _1, c o e f ) ) ;return * this ;
}
template <typename T, typename S>void oneDimOnMonomialMultiply (typename Polynomial<T, S>: :
OneDimStorage & data ,int monomialDegree ) {
data . i n s e r t ( data . begin ( ) , monomialDegree ,typename Polynomial<T, S>: : Coef ( ) ) ;
}
template <typename T, typename S>Polynomial<T, S> Polynomial<T, S>: : onMonomialMultiply (
typename Polynomial : : DegreeT const & monomialDegree ) const{
using namespace boost : : lambda ;Polynomial r e s (* this ) ;s td : : for_each ( r e s . c o e f s . begin ( ) , r e s . c o e f s . end ( ) ,
bind ( oneDimOnMonomialMultiply<T, S>, _1, monomialDegree[ 1 ] ) ) ;
r e s . c o e f s . i n s e r t ( r e s . c o e f s . begin ( ) , monomialDegree [ 0 ] ,OneDimStorage ( ) ) ;
64
r e s . degree += monomialDegree ;return r e s ;
}
template <typename T, typename S>typename Polynomial<T, S>: : CoefPolynomial<T, S>: : ProxyPolySeqProduct : : operator ( ) (
Point const & pt ) const {typename Polynomial : : Coef r e s = typename Polynomial<T, S>: : Coef
( ) ;for ( s i ze_t i = 0 ; i < poly . c o e f s . s i z e ( ) ; ++i )
for ( s i ze_t j = 0 ; j < poly . c o e f s [ i ] . s i z e ( ) ; ++j )r e s += poly . c o e f s [ i ] [ j ]
* seq ( Point ( i , j ) + pt − poly . getDegree ( ) ) ;return r e s ;
}/**************** End o f Ari thmet ic opera t i ons *****************/
template <typename T, typename S>typename Polynomial<T, S>: : DegreeTcountDegree (typename Polynomial<T, S>: : StorageT const & co e f s ) ;
template <typename T, typename S>void Polynomial<T, S>: : s e tCoe f s ( StorageT const & data ) {
c o e f s = data ;countDegree ( ) ;
}
template <typename T, typename S>typename Polynomial<T, S>: : ProxyPolySeqProduct Polynomial<T, S>: :
operator [ ] (Sequence<S> const & seq ) const {
return typename Polynomial<T, S>: : ProxyPolySeqProduct (* this ,seq ) ;
}
/*********** Degree−computing r e l a t e d rou t i n e s **************/template <typename T, typename S>void Polynomial<T, S>: : countDegree ( ) {
65
degree = f indLast InSeq ( c o e f s ) ;}/******* End o f Degree−coumting r e l a t e d rou t i n e s **********/
/****************** Streaming opera t i ons ******************/// format : [ [ a b c ] [ e f ] ]template <typename T, typename S>std : : i s t ream& operator>>(std : : i s t ream& is , Polynomial<T, S> & poly )
{typename Polynomial<T, S>: : StorageT data ;i f ( f i l l S t o r a g e ( i s , data ) )
poly . s e tCoe f s ( data ) ;return i s ;
}
template <typename T, typename S>std : : ostream& operator<<(std : : ostream& os , Polynomial<T, S> const &
poly ) {p r i n t ( os , poly . getCoe f s ( ) ) ;os << " degree : " << poly . getDegree ( ) ;return os ;
}/*************** End o f Streaming opera t i ons ****************/
} // namespace bmsa
GenericTwoDimIO.h
#ifndef _GENERICTWODIMIO_H#define _GENERICTWODIMIO_H
#include <iostream>#include <ios>
namespace bmsa {
template <typename TwoDimStorage>std : : i s t ream& f i l l S t o r a g e ( std : : i s t ream& is , TwoDimStorage& s t ) {
i f ( i s . peek ( ) == ’ [ ’ )
66
i s . get ( ) ;else
i s . s e t s t a t e ( std : : i o s : : f a i l b i t ) ;while ( i s ) {
char nextCh = i s . peek ( ) ;i f ( nextCh == ’ [ ’ )
i s . get ( ) ;else i f ( nextCh == ’ ] ’ ) {
break ;}else {
i s . s e t s t a t e ( std : : i o s : : f a i l b i t ) ;break ;
}typename TwoDimStorage : : value_type v ;while ( i s . peek ( ) != ’ ] ’ ) {
typename TwoDimStorage : : value_type : : value_type c ;i s >> c ;v . push_back ( c ) ;
}i s . i gno r e (2 , ’ ] ’ ) ;s t . push_back (v ) ;
}return i s ;
}
template <typename TwoDimStorage>std : : ostream& pr in t ( std : : ostream& os , TwoDimStorage const & data )
{os << ’ [ ’ ;for (
typename TwoDimStorage : : c on s t_ i t e r a to r v i t = data .begin ( ) ;
v i t != data . end ( ) ;++v i t
) {os << ’ [ ’ ;for (
typename TwoDimStorage : : value_type : : c on s t_ i t e r a to r
67
i t = vi t−>begin ( ) ;i t != vi t−>end ( ) ;++i t
) {os << * i t ;i f ( ( i t + 1) != vi t−>end ( ) )
os << ’ ’ ;}os << ’ ] ’ ;
}os << ’ ] ’ ;return os ;
}} // namespace bmsa#endif /* _GENERICTWODIMIO_H */
DeltaSet.h
#ifndef _DELTASET_H#define _DELTASET_H
#include <iostream>#include <i t e r a t o r >#include <l i s t >
#include <cstdde f>
namespace bmsa {
// d e l t a s e t o f exc luded po in t s −− based on some d e l t a s e t// which po in t s and the current sequence segment// de f i n e the exc luded po in t s o f four t ype s ;// ’ ( un) changed ’ be low −− compara t i ve l y wi th the po in t s o f// d e l t a s e t on which t h i s DS o f exc luded po in t s i s based on ;// type I : both coord ina t e s remain unchanged// type I I : both coord ina t e s changed// type I I I : f i r s t coord ina te changed// type IV : second coord ina te changedstruct DeltaSetPoint {
68
enum { I = 1 , I I , I I I , IV } ; // p o s s i b l e po in t t ype s
s i ze_t pointType ;
s i ze_t i ;
s i z e_t j ;
De l taSetPoint ( s i ze_t pointType_ , s i ze_t i_ , s i ze_t j_) :pointType ( pointType_ ) , i ( i_ ) , j ( j_ ) {}
} ;
inl inebooloperator<(DeltaSetPoint const & p1 , DeltaSetPoint const & p2 ) {
return p1 . pointType < p2 . pointType ;}
inl inestd : : ostream& operator<<(std : : ostream& os , Del taSetPoint const &
pt ) {os << "type : " << pt . pointType
<< " i=" << pt . i<< " j=" << pt . j ;
return os ;}
typedef std : : l i s t <DeltaSetPoint> DeltaSet ;
inl inestd : : ostream& operator<<(std : : ostream& os , DeltaSet const & ds ) {
std : : copy ( ds . begin ( ) , ds . end ( ) ,s td : : ostream_iterator<DeltaSetPoint >(os , "\n\ t " ) ) ;
os << std : : endl ;return os ;
}} // namespace bmsa#endif /* _DELTASET_H */
69
Sequence.h
#ifndef _SEQUENCE_H#define _SEQUENCE_H
#include <iostream>#include <vector>
#include "ElementType . h"#include "GenericTwoDimIO . h"#include "Point . h"
namespace bmsa {
template<typename ElemType = NTL: : GF2>class Sequence {public :
typedef ElemType ElemT ;typedef std : : vector< std : : vector<ElemT> > StorageT ;
Sequence ( std : : i s t ream& i s ) :DEFAULT_VAL( ElemTypeTraits<ElemT>:: Nul l ( ) )
{ i s >> * this ; }
Point s i z e ( ) const {return s ize_ ; }
ElemT const & operator ( ) ( Point const &) const ;private :
StorageT rep ;
Point s ize_ ;
const ElemT DEFAULT_VAL;
template <typename T>friendstd : : i s t ream& operator>>(std : : i s t ream& is , Sequence<T>& seq ) ;
template <typename T>
70
friendstd : : ostream&operator<<(std : : ostream& os , Sequence<T> const & seq ) ;
} ; // c l a s s Sequence
template <typename T>typename Sequence<T>::ElemTconst & Sequence<T>: : operator ( ) ( Point const & pt ) const {
i f ( pt [ 0 ] > static_cast<int>(rep . s i z e ( ) )| | pt [ 1 ] > static_cast<int>(rep [ pt [ 0 ] ] . s i z e ( ) ) )
return DEFAULT_VAL;return rep [ pt [ 0 ] ] [ pt [ 1 ] ] ;
}
template<typename T>inl inestd : : i s t ream& operator>>(std : : i s t ream& is , Sequence<T>& seq ) {
typename Sequence<T>:: StorageT s t ;i f ( f i l l S t o r a g e ( i s , s t ) )
seq . rep = s t ;seq . s ize_ = ++f indLast InSeq ( seq . rep ) ;return i s ;
}
template<typename T>inl inestd : : ostream& operator<<(std : : ostream& os ,
Sequence<T> const & seq ) {p r i n t ( os , seq . rep ) ;return os ;
}
} // namespace bmsa
#endif /* _SEQUENCE_H */
Point.h
#ifndef _POINT_H
71
#define _POINT_H
#include <algorithm>#include <cas s e r t >#include <cstdde f>#include <iostream>#include <numeric>#include <vector>#include <tr1 /array>
#include <boost /lambda/lambda . hpp>
namespace bmsa {
class Point {stat ic const s i ze_t DIMENSION = 2 ;
typedef std : : t r1 : : array<int , DIMENSION> ComponetsStorageT ;ComponetsStorageT data ;
public :stat ic Point n i l ;
Point ( ) {data [ 0 ] = 0 ;data [ 1 ] = 0 ;
}
Point ( int x , int y ) {data [ 0 ] = x ;data [ 1 ] = y ;
}
int weight ( ) const {return std : : accumulate ( data . begin ( ) , data . end ( ) , 0) ;
}
// s u b s c r i p t opera tor sComponetsStorageT : : r e f e r e n c e
72
operator [ ] ( ComponetsStorageT : : s ize_type n) {a s s e r t ( 0 <= n && n < DIMENSION) ;return data [ n ] ;
}
ComponetsStorageT : : cons t_re f e r ence operator [ ] (ComponetsStorageT : : s ize_type n) const {
a s s e r t ( 0 <= n && n < DIMENSION) ;return data [ n ] ;
}
inl inebool operator==(Point const & rhs ) const {
return ( data == rhs . data ) ;}
Point& operator+=(Point const & rhs ) {data [ 0 ] += rhs . data [ 0 ] ;data [ 1 ] += rhs . data [ 1 ] ;return * this ;
}
Point& operator−=(Point const & rhs ) {data [ 0 ] −= rhs . data [ 0 ] ;data [ 1 ] −= rhs . data [ 1 ] ;return * this ;
}
Point& operator++() ;
Point operator++(int ) ;
friend // p a r t i a l o rder ingbool byComponentLessOrEqual ( Point const &, Point const &) ;
friendstd : : ostream& operator<<(std : : ostream& os , Point const &) ;
} ;
73
inl inebool operator !=( Point const & lhs , Point const & rhs ) {
return ! ( l h s == rhs ) ;}
// by component l e s sinl inebool operator<=(Point const & lhs , Point const & rhs ) {
return l h s [ 0 ] <= rhs [ 0 ] && lh s [ 1 ] <= rhs [ 1 ] ;}
inl inebool operator<(Point const & lhs , Point const & rhs ) {
return ( l h s <= rhs ) && ( lh s != rhs ) ;}
inl inebool t o t a lL e s s ( Point const & lhs , Point const & rhs ) {
int lhsPow = lh s . weight ( ) ;int rhsPow = rhs . weight ( ) ;i f ( lhsPow == rhsPow )
return l h s [ 0 ] > rhs [ 0 ] ;else
return lhsPow < rhsPow ;}
inl inebool tota lLessOrEqual ( Point const & lhs , Point const & rhs ) {
return l h s == rhs | | t o t a l L e s s ( lhs , rhs ) ;}
inl inePoint operator+(Point lhs , Point const & rhs ) {
// l h s : pass−by−copy op t im i za t i onreturn l h s += rhs ;
}
inl inePoint operator−(Point lhs , Point const & rhs ) {
74
return l h s −= rhs ;}
template< typename OneDimStorage >int lastInOneDim ( OneDimStorage const & data ) {
using namespace boost : : lambda ;int deg = data . rend ( )
− std : : f i nd_ i f ( data . rbeg in ( ) , data . rend ( ) ,_1 != typename OneDimStorage : : value_type ( ) )
− 1 ;return deg > −1 ? deg : 0 ;
}
template< typename TwoDimStorge >Point f indLast InSeq (TwoDimStorge s to rage ) {
i f ( s t o rage . empty ( ) )return Point ( ) ;
typedef std : : vector<Point> PtStorage ;PtStorage po in t s ;int i = 0 ;for (
typename TwoDimStorge : : c on s t_ i t e r a to r v i t = s to rage .begin ( ) ;
v i t != s to rage . end ( ) ;++vit , ++i ) {
int lessDimDegree = lastInOneDim (* v i t ) ;po in t s . push_back ( Point ( i , lessDimDegree ) ) ;
}
return// us ing t o t a l order ing on Point type :*( std : : max_element ( po in t s . begin ( ) , po in t s . end ( ) , t o t a lL e s s
) ) ;}
} // namespace bmsa#endif /* _POINT_H */
75
Point.cc
#include <func t i ona l >#include <numeric>#include <sstream>
#include <boost /lambda/lambda . hpp>
#include "Point . h"
namespace bmsa {
Point Point : : n i l = Point ( ) ;
inl ineboolbyComponentLessOrEqual ( Point const & lhs , Point const & rhs ) {
using namespace boost : : lambda ;return
std : : inner_product ( l h s . data . begin ( ) , l h s . data . end ( ) ,rhs . data . begin ( ) ,true , // i n i t va luestd : : log ica l_and<bool>() ,_1 <= _2) ;
}
std : : ostream& operator<<(std : : ostream& os , Point const & pt ) {os << ’ ( ’ ;s td : : o s t r ing s t r eam oss ;copy ( pt . data . begin ( ) , pt . data . end ( ) ,
s td : : ostream_iterator<int>(oss , " , " ) ) ;s td : : s t r i n g s = oss . s t r ( ) ;s td : : s t r i n g s s ( s . begin ( ) , −−(s . end ( ) ) ) ;os << ss << ’ ) ’ ;return os ;
}
Point& Point : : operator++() {i f ( data [ 0 ] == 0) {
76
data [ 0 ] = data [ 1 ] + 1 ;data [ 1 ] = 0 ;
} else {−−data [ 0 ] ;++data [ 1 ] ;
}return * this ;
}
Point Point : : operator++(int ) {Point o ld (* this ) ;++*this ;return old ;
}
} // namespace bmsa
ElementType.h
#ifndef _ELEMENTTYPE_H#define _ELEMENTTYPE_H
namespace bmsa {
template <typename T>struct ElemTypeTraits {
stat ic T id ( ) {T r e s = T( ) ;return ++re s ;
}
stat ic T Null ( ) {return T() ;
}} ;} // namespace bmsa#endif /* _ELEMENTTYPE_H */
77