Программирование основ вычислительной алгебры на языке с зависимыми типами

ISSN 2079-3316 ПРОГРАММНЫЕ СИСТЕМЫ: ТЕОРИЯ И ПРИЛОЖЕНИЯ №4(27), 2015, с. 313-340 УДК 510.252, 004.432.42

С. Д. Мешвелиани

Программирование основ вычислительной алгебры на языке с зависимыми типами

Аннотация. В статье описываются главные черты разработанной автором на основе доказательного программирования библиотеки вычислительной алгебры. Обсуждается опыт доказательного программирования некоторых классических категорий вычислительной алгебры («группа», «кольцо» и так далее) на основе подхода конструктивизма, применения языка с зависимыми типами, построения машинно-проверяемых доказательств (dependent types, proof carrying code). Выявляются проблемы, связанные с этим подходом, и отмечаются дополнительные возможности, даваемые применением аппарата зависимых типов. В качестве инструмента используется функциональный язык Agda. Статья является продолжением вводной статьи автора в данном журнале за 2014 год.

Ключевые слова и фразы: конструктивная математика, алгебра, зависимые типы, функциональное программирование, Agda.

Введение

В первой части [1] исследования применяется подход конструктивной математики [2] и конструктивной теории типов [3] к программированию некоторых методов вычислительной общей алгебры. На этих примерах описываются главные черты чисто функционального языка Agda [4,5], воплощающего подход интуиционистской теории типов.

Как только применены зависимые типы, алгоритмы (программы) естественным образом соединяются с доказательствами. И появляется возможность доказуемого программирования, когда заданные свойства

Исследование выполнено в рамках НИР «Методы анализа и верификации моделей вычислительных систем и алгебраических объектов на основе средств функционального и логического программирования» (№ г/р 01201354590) и «Методы и средства разработки эффективного программного обеспечения, ориентированные на вычислительные системы, построенные на основе микропроцессоров с многоядерной архитектурой, и формальные основы высокоуровневых языков программирования для суперкомпьютеров с гибридной архитектурой» (№ г/р 01201455360) (госзадание ФАНО России). © С. Д. Мешвелиани, 2015

© Институт программных систем имени А. К. Айламазяна РАН, 2015 © Программные системы: теория и приложения, 2015

алгоритма автоматически проверяются компилятором (точнее — прове-ряльщиком типов). Более определённо, зависимые типы дают возможность:

• выражать свойство Р алгоритма в виде типа Т (зависящего от значений), причём конструкторы для Т задаются программистом,

• выражать доказательство свойства Р в виде функции, строящей любое значение в Т,

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

• полагаться на автоматическую проверку доказательств,

• строить и надёжно автоматически проверять многие доказательства теорем в математике (ибо утверждения выражаются в виде зависимых типов).

Здесь описываются главные черты первой очереди библиотеки вычислительной алгебры, построенной автором на основе аппарата зависимых типов и программирования на языке Agda. Предполагается развитие этой программной системы.

Обсуждаемая здесь библиотека программ вычислительной алгебры ЭоСоп-А написана на языке Agda, содержит описания алгоритмов и машинно-проверяемые доказательства их важнейших свойств, то есть автоматическую верификацию. Этот подход соответствует изложению алгоритмических методов алгебры в стиле учебника, вместе с определениями и доказательствами. Но разница состоит в том, что алгоритмы представлены в виде программ, определения и доказательства составляют часть программы и воспринимаются компилятором, доказательства являются полными и формальными, и проверяются компилятором.

Ближайшей целью работы является проверка практической возможности программирования на языке Agda некоторой начальной части библиотеки вычислительной алгебры, включающей полные доказательства. Эта проверка даёт ответы на следующие вопросы.

• Каковы выразительные возможности языка Agda: насколько математически адекватна запись определений и доказательств.

• Какова трудоёмкость составления машинно-проверяемых доказательств.

• Каков объём части исходной программы, воплощающей доказательства, по сравнению с объёмом соответствующего учебника, содержащего строгие (в обычном смысле) доказательства.

• Каковы затраты памяти и времени на проверку типов и компиляцию.

В конце статьи приводятся ответы на эти вопросы.

Последующее изложение опирается на

• понятия о чисто функциональном программировании, например,

на языке Haskell, о «ленивом» способе вычисления,

• сведения о главных чертах языка и системы

Agda [4],

• изложение вводной статьи [1],

• общие понятия об алгебре [6],

• сведения о вычислительной алгебре [7,8].

Сокращения: библиотеку программ DoCon-A будем сокращённо называть «библиотека».

«Стандартная библиотека» означает стандартную библиотеку языка Agda.

О символах и именах в языке Agda: приводимые в этой статье отрывки кода содержат математические символы и применяют систему языка Agda для задания идентификаторов. Эта система обозначений объясняется в [1], раздел 1.1.

1. Башня общих алгебраических структур

В настоящее время библиотека содержит определения и алгоритмы для некоторой иерархии классических общих алгебраических структур: от разрешимого множества (DSet), магмы (Magma) и полугруппы (Semigroup) до евклидова кольца (EuclideanRing) и поля (Field). Эта иерархия выражается графом, представленным ниже на рис. 1.

Пользователь библиотеки может её расширять, например, добавляя свои структуры к данной иерархии.

Нисходящие рёбра в этом графе означают наследование структур. Например, полугруппа должна иметь структуру магмы и ещё иметь добавочную структуру, выражающую ассоциативность операции. Два ребра, входящие в вершину Ringoid (пред-кольцо) выражают то, что пред-кольцо есть коммутативная группа по сложению (_+_) и магма по умножению (_*_). В этом графе пропущены некоторые законы, входящие в определения стуктур и в программу. Например: закон дистрибутивности для кольца.

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

/ множество с разрешимым 3et (

V отношением равенства

4,

RingWithOne

4-

CommutativeRing

4.

IntegralRing

I

GCDRing---

UniqueFactorizationRing --- EuclideanRing

4,

Field

Рис. 1. Башня общих алгебраических структур

остатков по идеалу в кольце многочленов над евклидовым кольцом, разложение на простые множители многочлена над различными полями. Другой причиной выбора этой области является та, что ранее автором разработана на языке Haskell библиотека DoCon [9], которая посвящена в основном вычислениям в вышеназванных структурах. А библиотека DoCon-A разрабатывается как более адекватное выражение библиотеки DoCon. Усиление состоит в следующих двух главных дополнительных возможностях, даваемых аппаратом зависимых типов.

(1) Адекватное выражение конструкции алгебраической области, зависящей от динамически вычисляемых значений ([1], раздел 0.2).

(2) Возможность доказательного программирования с машинно проверяемыми доказательствами.

Причём даже при отсутствии части (2) получается существенное улучшение способа программирования.

2. Разрешимый сетоид

Сетоид определён в стандартной библиотеке языка Agda как множество (Carrier) с отношением _и_ равенства (эквивалентности) на нём. Это определение выражено в виде типа — записи (record). Отношение _и_ программируется пользователем для каждого случая сетоида. Например, программа для равенства многочленов может включать приведение подобных членов, так что, например, будет выполнено равенство (x + 2 * x) и (3 * x).

Там же в стандартной библиотеке определён разрешимый сетоид DecSetoid — сетоид с добавленным алгоритмом _=_ разрешения для отношения

Библиотека ставит разрешимый сетоид в основу башни алгебраических структур, для которых задаются методы вычислений. Например, полугруппа определяется только на разрешимом сетоиде. Причина для такого подхода есть та, что при отсутствии разрешимого равенства (_=_) для арифметики невозможны почти никакие алгоритмические методы. Например, при сложении двух квадратных многочленов окажется невозможным определить степень суммы.

3. Конечное перечисление и бесконечное множество

В алгебре особое место занимают конечные структуры; для них доказано много замечательных утверждений и разработаны многие особо эффективные алгоритмы. Свойство конечности алгебраической области в системе DoCon-A выражено в виде наличия перечисляющего списка для носителя (Carrier) области:

- .Agda —

1 record FiniteEnumeration (A : Setoid) : Set

2 where

3 constructor finEnum'

open Setoid A using

5 open Membership2 A using

6

7 field

8 list : List Carrier

9 card : N

10 proofs : (— AnyRepeats list) X IsFullList A list X length list = card

(здесь и ниже пропускаются некоторые мало-существенные подробности кода).

В этой записи

Set есть множество всех типов (объяснения имеются в [4]) (так что

допускаются функции, имеющие типы в качестве значений), A есть параметр (аргумент) — сетоид, Carrier есть его носитель. Для каждого определённого пользователем примера структуры (в данном случае, записи FiniteEnumeration) пользователь должен задать программы вычисления значений полей этой структуры, то есть — частей, стоящих под ключевым словом field (в данном случае, значений list, card, proofs). list есть перечисляющий список для носителя,

card есть мощность множества Carrier (относительно отождествления _«_) — натуральное число. proofs состоит из свидетельств (доказательств) для трёх утверждений (конъюнкция утверждений в конструктивной логике выражается в виде прямого произведения _х_ типов):

(1) свидетельство для утверждения об отсутствии повторов в списке list;

(2) свидетельство для утверждения о том, что список list является полным для носителя;

(3) свидетельство для равенства мощности носителя длине списка list.

Каждое из этих утверждений выражено в виде задания соответствующего типа данных.

Например, приведём определение для второго утверждения:

- Agda —

1 IsFullList : (A : Setoid) ^ List (Setoid.Carrier A) ^ Set

2 IsFullList A xs = (x : Setoid.Carrier A) ^ x G xs

3 where

open Membership A using

Этот тип данных представляет утверждение

«Всякий элемент x носителя равен в смысле некоторому элементу списка xs».

Отношение _g_ принадлежности списку определено в параметрическом модуле Membership из стандартной библиотеки.

Определение для первого утверждения мы пропускаем ради упрощения изложения.

Итак, видим, что определение конечного перечисления области выражено в виде типа данных — записи. Поля этой записи зависят как от «обычного» значения (натурального числа), так и от некоторых значений — свидетельств. Причём между этими значениями заданы зависимости. Это построение называется зависимая запись (dependent record) — частный случай зависимого типа (dependent type). Эта конструкция языка обладает такой математической выразительностью, какой нет в языках предыдущего поколения (например, в языках Haskell, ML).

3.1. Доказательно бесконечное множество

Конструктивное понятие бесконечности множества библиотека определяет в виде типа Infinite некоторых отображений из типа списков над носителем C сетоида:

- .gda —

1 Infinite : Set

2 Infinite = (xs : List C) ^ 3 \x ^ x 0 xs

Всякий элемент типа Infinite есть (алгоритмическое) отображение, которое для каждого списка xs над C выдаёт пару (x , x0xs), где x принадлежит C (x : c), а x0xs есть свидетельство того, что x не принадлежит списку xs в смысле равенства _и_ (x 0 xs).

Пример: библиотека использует следующее доказательство бесконечности множества натуральных чисел.

Алгоритм getOutOfList принимает список xs : List N, находит m = maximum (0 :: xs) и выдаёт пару (m' , m'0xs), где m' = m + 1, a m'0xs есть свидетельство того, что m' не принадлежит списку xs. Исходный текст этой функции

- .gda —

getOutOfList : (xs : List N) ^ 3 \x ^ x 0 xs

занимает 20 непустых строк, и его главная часть представляет конструктивное доказательство того, что каждый элемент списка xs меньше числа (maximum (о :: xs)) + 1. Доказательство использует функцию maximum, которая в библиотеке запрограммирована в отдельном модуле для общего случая полного разрешимого упорядочения (DecTotalOrder) и которая кроме максимума m для непустого списка xs выдаёт свидетельства для утверждений

Agda

m G xs, All (\x ^ x < m) xs

3.2. Множество с разрешённым свойством конечности

Следующий безымянный параметрический модуль выражает понятие алгоритмически разрешённого свойства конечности множества:

- Agda —

module _

2 where

3 private C = Setoid.Carrier A open Membership A using

6 Infinite : Set

7 Infinite = (xs : List C) \x ^ x 0 xs

8

9 data DecFiniteEnumeration : Set

10 where

11 finEnum : FiniteEnumeration A ^ DecFiniteEnumeration

12 infinite : Infinite ^ DecFiniteEnumeration

Здесь тип данных DecFiniteEnumeration описывает все возможные свидетельства для конечности или бесконечности множества C в смысле равенства _«_. Значение вида (finEnum en) из этого типа означает, что en : FiniteEnumeration A есть конечное перечисление для носителя C (как оно определено выше). Значение (infinite inf) из этого типа означает, что inf есть свидетельство бесконечности C (как оно определено выше).

4. Разрешимое множество

Библиотека ставит разрешимое множество (структура в основу башни алгебраических структур. Разрешимое множество определяется как запись из полей 1) разрешимый сетоид decS, 2) функция распечатки элемента в строку, 3) возможное разрешённое свойство конечности:

- .gda —

1 record DSet (decS : DecSetoid) : Set

2 where

3 open DecSetoid decS using

5 field showInstance : Show Carrier

6 mbFiniteEnum : Maybe $ DecFiniteEnumeration setoid

Разрешимый сетоид decS даётся в аргументе записи. Программист задаёт функцию showInstance для распечатки всевозможных результатов. Для некоторых конструкторов типа она запрограммирована в библиотеке.

Тип поля mbFiniteEnum отличается от разрешённой конечности конструктором Maybe — «может быть». Значение вида ( ( )) этого поля означает, что en есть конечное перечисление для носителя.

Значение (just (infinite inf)) означает, что inf есть свидетельство бесконечности носителя.

Значение nothing означает: «не известно ни конечного перечисления носителя, ни конструктивного доказательства его бесконечности».

4.1. Формат «может-быть»

Введение формата «может-быть» для некоторых операций вызвано двумя причинами.

(1) Разрешимые множества появляются как конструкции над типами, зависящими от значений, а значения часто появляются в ходе вычисления, они могут быть неизвестны до начала выполнения программы. Наличие или отсутствие конечного перечисления зависит от этих значений. Проблема определения наличия конечного перечисления в зависимости от этих значений в общем случае не имеет алгоритмического решения. Например: определение конечности кольца остатков алгебры многочленов от переменных [x, y, z] по модулю данного набора уравнений (в зависимости от этих уравнений) может быть тяжёлой проблемой.

(2) Во многих структурах (скажем, в кольце) некоторые операции в том или ином случае этой структуры легко задать алгоритмом (скажем, о, +, *), а найти алгоритм для других операций этой структуры (скажем, поиск делителя нуля) является проблемой. Надо ещё учитывать, что случай структуры может зависеть от значений, которые могут быть неизвестны до начала выполнения программы.

Эти два затруднения разрешаются введением формата «может-быть» для некоторых операций.

5. Магма

Для сетоида S, двуместной операции _•_ на его носителе C и элементов a и ь из C правое частное a по ь определяется в виде типа

- Agda —

1 RightQuotient : C ^ C ^ Set

2 RightQuotient a b = 3

В стандартной библиотеке знак существования 3 имеет конструктивный смысл. Так, в данном случае частное есть пара (q , e), где q : C, а e есть свидетельство для равенства ь • q и a.

Магма есть разрешимое множество с двуместной операцией (обозначаемой _•_) конгруентной относительно отношения равенства:

- Agda —

1 record Magma (upDS : UpDSet) : Set

2 where

3 private dS = UpDSet.dSet upDS

open DSet dS using ^equiv; _и_) renaming

5 и^^ = IsEquivalence.refl ^quiv -- закон рефлексии равенства

6

7 field _•_

8 »cong

9 mbCommutative 0 divRightMb

11

2 »congx : y : C ^ (\x ^ x • y) Preserves _и_->_и_

3 »congx x=x' = »cong x=x' ^efl

4

_|_ : Rel C _

6 x | y = RightQuotient S _•_ y x -- <<x делит y>> 17

8 ...

Op2 C

_•_ Preserves2 _и_->_и_->_и_

Maybe $ DecCommutative S _•_

(x y : C) ^ Maybe $ Dec $ RightQuotient S _._ x y

Здесь четыре поля записи (под ключевым словом field) составляют определение магмы. Они суть отвлечённые операции. От программиста требуется задать реализацию этих операций в виде программ (функций) для каждого используемого случая этой структуры.

Так, в данном случае _•_ есть операция магмы вообще, a для магмы натуральных чисел по умножению подставляется _•_ = _*_, и программируется умножение _*_ для натуральных чисел.

Но имеются ещё дополнительные значения: типы данных и функции. Такие дополнительные сущности бывает удобно включать в общую структуру (запись), так как запись может быть использована как программный модуль. Эти дополнительные сущности получают реализацию уже в теле общей структуры и не требуют программирования для случаев этой структуры.

Продолжим объяснение записи Magma.

Поле «cong выражает закон конгруентности.

Поле mbCommutative выражает возможное свойство коммутативности операции _•_.

Поле divRightMb выражает (расширенную частичную) операцию деления в магме. Её итог вида (just (yes quot)) означает, что quot есть правое частное, включающее свидетельство.

Итог вида (just (no noQuot)) означает, что noQuot есть свидетельство отсутствия правого частного.

Итог вида nothing означает отсутствие сведений о частном x по y (в некоторых областях поиск частного является тяжёлой алгоритмической проблемой).

Пример: для магмы натуральных чисел по умножению имеем

- Agda —

divRightMb 6 2 = just

где 2*3=6 : 2*3 = 6 и

- Agda

Quot-6-4 : — RightQuotient natSetoid _*_ 6 4

2

суть соответствующие свидетельства.

Дополнительная функция «со^ есть лемма, которая сопровождает определение магмы. Её реализация (в виде одной строчки) есть доказательство конгруентности операции _•_ по первому аргументу. Выносить ли ту или иную лемму в отдельный модуль или оставить её в теле определяемой структуры — есть дело вкуса разработчика библиотеки.

Дополнительный тип определяет отношение делимости на магме.

О выборе набора операций: поля _•_ и •cong дол^кны присутствовать в любой версии определения магмы, ибо они дают классическое определение. Набор других полей есть дело вкуса разработчика библиотеки алгебры. Например, можно было бы включить частичный атрибут порождающего множества элементов, функцию периода элемента, и так далее.

6. Отступление: up-структуры

Очередная техническая проблема такова:

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

Например: два векторных пространства над одним и тем же полем коэффициентов.

В математике такой проблемы нет: пишется просто «Пусть U и V суть векторные пространства над полем F».

В разрабатываемой библиотеке алгебраическая структура представляется записью (record), наследование структур представлено включением одной записи в качестве поля в другую запись. Такое представление выглядит простым и естественным, и другого разумного представления не видно. Но тогда необходимо выразить то отношение, что две записи имеют равные значения некоторого поля записи, где это значение есть некоторая алгебраическая структура (например, полугруппа). Задать алгоритмическое равенство на таких структурах не представляется возможным. Но нужное отношение просто выражается введением в объявление структуры аргумента в виде переменной. Например, выше запись Magma зависит от аргумента, обозначенного переменной upDSet. Тогда строки

- Agda —

1 M1 : Magma upDS

2 M2 : Magma upDS

объявляют что магмы M1 и M2 определены на одном множестве.

Далее: полугруппа получит в аргументе магму, группа получит в аргументе полугруппу, кольцо получит в аргументах коммутативную группу по сложению и полугруппу по умножению (имеющие общее множество), и так далее. Этот естественный подход ведёт к следующему неожиданному явлению. Например, в объявлении вида

- Адйа —

Е : ЕисИдеапИз.^ <аргументы>

каждая структура - аргумент должна сопровождаться её собственными аргументами. Уровень вложенности структур велик, и это приведёт к неприемлемо большому выражению для того, что в учебниках коротко выражается предложением «Пусть E есть евклидово кольцо».

И вот: применение ир-структур позволяет убрать упоминание аргументов структур тогда, когда это нужно, и таким образом позволяет

• выразить наследование через включение структур,

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

• сделать размер объявления структуры таким же малым, как в учебниках алгебры.

Техника ир-структур состоит в следующем.

В аргументе записи Magma стоит структура upDS : UpDSet, которая до сих пор не описана и которая есть ир-разновидность разрешимого множества (DSet):

- Agda —

1 record UpDSet : Set where

2 field decSetoid : DecSetoid

3 dSet : DSet decSetoid

4

5 open DSet dSet public hiding

Запись DSet зависит от аргумента типа DecSetoid, а в записи UpDSet значение этого аргумента подставляется из поля decSetoid. Соответственно, запись UpDSet не требует аргумента. Далее:

Magma имеет аргумент upDSet : UpDSet,

UpMagma имеет поля upDSet : UpDSet и magma : Magma upDSet, Semigroup имеет аргумент upMagma : UpMagma,

UpSemigroup имеет поля upMagma : UpMagma и semigroup : Semigroup magma.

и так далее: Group - UpGroup, Ring - UpRing, . . .

ир-структуры не имеют аргумента.

Пример: векторное пространство (структура VectorSpace) определено для поля f : Field коэффициентов и коммутативной группы G векторов.

В библиотеку понадобится включить определение общего понятия линейного отображения f : U ^ V пространств. Для этого необходимо выразить требование того, что они суть пространства над одним и тем же полем F. А естественное выражение нужного понятия берём из учебников алгебры: структура VectorSpace имеет аргументами (параметрами) структуру поля коэффициентов и структуру коммутативной группы G векторов.

Например, для функции f двух векторных пространств над одним полем объявление (сигнатура) выглядит так:

- Agda —

1 f : (upF : upField) ^ (upGU upGV : UpCommutativeGroup) ^

2 (U : VectorSpace upF upGU) ^ (V : VectorSpace upF upGV) ^ ...

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

Заметим, что стандартная библиотека применяет другой подход. Но в её подходе появляются парные структуры: Semigroup - IsSemigroup, Group - isGroup, и так далее. Причем обе части пары имеют одинаково объёмные выражения.

7. Отступление: отношение к стандартной библиотеке

Стандартная библиотека языка Agda тщательно продумана, содержит базовые определения и леммы присущие самым общим конструкциям: отношениям, отображениям, спискам, и так далее. Она очень полезна в применении. Она также имеет набор общих алгебраических

структур: Semigroup, Monoid, Group, AbelianGroup, Ring, CommutativeRing.

По этой небольшой части две библиотеки пересекаются. ЭоСоп-А импортирует эти стандартные структуры, переименовывая их добавлением окончания -stdlib. Например, Group-stdlib. Кроме того, ЭоСоп-А предоставляет функции перевода в stdlib - структуры. Например, функция

- Адйа —

ringWithOne-toStdlib : ИрМ^УгЬШпе ^ Ring-stdlib

преобразует в кольцо с единицей стандартной библиотеки.

Различие на этом пересечении вызвано тем, что библиотека ЭоСоп-А разрабатывается как продвинутое приложение, она содержит гораздо больше алгебраических структур и алгебраических методов (и будет расти). А общие со стандартом алгебраические структуры наделяются некоторыми дополнительными операциями. Это вызвано тем, что практическая алгоритмическая алгебра в отличие от классической учитывает требования удобства задания вычисления и сбережения объёма вычисления.

Пример: в классической теории моноид имеет две операции: _•_ и £ (единица). А библиотека ЭоСоп-А добавляет в моноид операцию обобщённого возведения в степень, вместе с двумя законами для неё:

- Адйа —

V хп

Можно было бы вынести операцию в отдельный модуль, использующий структуру классического моноида, и запрограммировать её через двоичный способ возведения в степень. Но решение в библиотеке более гибкое. Например, для аддитивного моноида натуральных чисел операцию естественно реализовать как умножение _*_, и вычисление будет значительно быстрее, чем двоичный способ с повторным сложением. В целом:

(1) отличия от классических определений вызваны необходимостью поддержки задания эффективных алгоритмов,

(2) всякая общая алгебраическая структура библиотеки влючает в себя все операции из классического определения.

8. Полугруппа, моноид

Продолжим описание представления алгебраических структур.

Полугруппа определяется как ассоциативная магма:

- Agda —

record Semigroup (upMg : UpMagma) : Set

2 where

3 private open UpMagma upMg using

(isEquivalence; setoid; _:_; _•_; _|_; •congi) module FP: = FuncProp _:_

open EqR setoid renaming

7

8 open IsEquivalence isEquivalence using

9

10 field •assoc : FP:.Associative _•_ -- главная часть определения

12 open UpMagma upMg public

13

14 -- Лемма, добавленная <<на месте>> -------------------------------------

16 !• : V x y z ^ x | y ^ x |

17 !• x y z

18 where

19 x^qz=yz : x • (q • z) : y • z

20 x^qz=yz = begin x • (q • z) :[ :sym $ •assoc x q z ]

21 (x • q) • z :[ •congi x^q=y ]

22 y • z

23 С

Здесь используется определение ассоциативности FP:.Associative, данное в стандартной библиотеке.

Лемма же утверждает и доказывает: "для любых x, y, z, если в полугруппе x делит y, то x делит (y • z)".

Построение похожего доказательства объясняется в [1] (раздел 1.5). Далее, единица в магме определяется функциями

- Agda —

1 isUnity : C ^ Set

2 isUnity e =

3

4 Unity : Set

5 Unity = 3 \(e : C) ^ isUnity e

Моноид есть полугруппа, обладающая единичным элементом:

- Agda —

1 record Monoid (upSmg : UpSemigroup) : Set

2 where

open UpSemigroup upSmg using

4 renaming

5

6 field unity : Unity S _•_

7

8 s : C

9 £ = projl unity

1С

11 field invMb : (a : C) ^ Maybe $ Dec $ Inverse upMg £ a

_"_ : C ^ N ^ C 13 "-0 : V x ^ (x ~ 0) и £

"-suc : V x e ^

15

16 -- Леммы <<на месте>> -----------------------------------------------

17

18 slaw : (x : C) ^ (e • x) и x X (x • e) и x

19 slaw = proj2 unity

2С

21 £• : (x : C) ^ (e • x) и x

22 £• = projl 0 £law

23

24 •£ : (x : C) ^ (x • e) и x

25 •£ = proj2 0 slaw

Аргумент upSmg и операция unity (включающая свидетельство для закона единицы) составляют классическое определение моноида.

Определение Inverse обратного элемента подобно описанному выше определению RightQuotient.

invMb есть операция частичного обращения: некоторые элементы имеют обратные относительно умножения.

Возведение в степень _"_ и его законы обсуждались выше.

Единица £ : C и закон умножения £law на неё извлекаются из данного unity.

Доказательства лемм £• и •£ используют две проекции закона

Slaw.

9. Группа, кольцо

Группа есть моноид с законом обращения:

- Agda —

record Group (upMon : UpMonoid) : Set

2 where

3 monoid = UpMonoid.monoid upMon

private open Monoid monoid using (setoid; _«_; «equiv; _•_; •assoc;

5 unity; s; •congi)

6 renaming

8

9 «sym = IsEquivalence.sym «equiv

10 eProofMap = proj2 unity

11

12 field inverse : (a : C) ^ Inverse upMg £ a -- главное в определении

13

14 -------------------------------------Дополнительные функции и леммы --

_-1 : C ^ C

16 1 = proji о inverse

17

18 divide : (a b : C) ^ RightQuotient setoid _•_ a b

19 divide a b with inverse b

21 where

22 qProof : (b • (i • a)) и a

qProof = begin b • (i • a) и[ «sym $ •assoc _ _ _ ]

24 (b • i) • a и[ •congi lProof ]

25 £ • a и[ proji $ eProofMap a ]

26 a

27 С

28 _/_ : Op2 C

29 x / y = proji $ divide x y

30

31 open Monoid monoid public

Здесь классическая (постфиксная) операция обращения _ 1 извлечена из операции расширенного обращения inverse.

Расширенное деление divide запрограммировано через операцию inverse, и оно включает доказательство свойства частного.

Классическое частное x / y извлекается из итога расширенного деления.

Коммутативная группа есть группа с добавленным законом коммутативности:

- Agda —

1 record CommutativeGroup (upG : UpGroup) : Set

2 where

3 group = UpGroup.group upG

private open Group group using (upSemigroup; upMonoid; _и_; _•_) module РРи = FP _и_

6

7 field commutative : FP^Commutative _•_

8

9 commutativeMonoid : CommutativeMonoid upMonoid 10 commutativeMonoid = commMonoid' commutative

12 commutativeSemigroup : CommutativeSemigroup upSemigroup

13 commutativeSemigroup = CommutativeMonoid.commutativeSemigroup

14 commutativeMonoid

15 open Group group public

Пред-кольцо (Ringoid) есть коммутативная группа по сложению и магма по умножению, причём эти две структуры определены на одном разрешимом множестве:

- Agda —

1 record Ringoid (upA : UpCommutativeGroup) : Set

2 where

3 +commGroup = UpCommutativeGroup.commutativeGroup upA open CommutativeGroup +commGroup using

5 renaming (Carrier to C; magma to +magma;

6 monoid to +monoid; upGroup to +upGroup)

7

8 field *magma : Magma upDSet

9 -----

10

11 0 = Monoid.г +monoid -- нуль пред-кольца

12 _+_ = Magma._^_ +magma -- сложение пред-кольца

13 _*_ = Magma._^_ *magma -- умножение пред-кольца

14

15 +cong = Magma.•cong +magma -- переобозначение закона конгруентности

16

17 -_ : C C -- взятие противоположного элемента

18 -_ = CommutativeGroup._-1 +commGroup

19

Структура пред-кольца введена для того, чтобы, например, охватить алгебры Ли: алгебра Ли является пред-кольцом относительно операций _+_ и [,], но не является кольцом.

Аргумент upA и операция *magma составляют ядро определения, а всё остальное извлекается из этих данных.

То условие, что группа upA и мультипликативная магма *magma определены над одним множеством, обеспечено

• импортом значения коммутативной группы +commGroup из upA,

• импортом значения upDSet через объявление open из +commGroup,

• объявлением *magma : Magma upDSet. .

Кольцо есть пред-кольцо, в котором выполнен закон дистрибутивности и в котором мультипликативная магма является полугруппой:

- Agda —

1 record Ring (upRd : UpRingoid) : Set

2 where

3 ringoid = UpRingoid.ringoid upRd

4

open Ringoid ringoid using

7 renaming

8

9 field *semigroup : Semigroup *upMagma

10 -----

12 *upSemigroup = upSemigroup' *upMagma *semigroup

13

open Power *upSemigroup using

16 field distributive : _DistributesOver_ _и_ _*_ _+_

17 mbZeroDivisor : Maybe $ Dec $ HasZeroDivisor upRd

18

19 IsNilpotent : C ^ Set

20 IsNilpotent a = a « 0 X

21 where

22 "suc = X n ^ " + X (suc n) suc>0

23 HasNilpotent : Set

24 HasNilpotent = 3 \a^ IsNilpotent a

Понятия «делитель нуля» ( ZeroDivisor) и «пред-кольцо имеет делитель нуля» ( HasZeroDivisor) определены раньше в условиях пред-кольца. Частичная операция mbZeroDivisor программируется в каждом случае кольца так, чтобы по возможности разрешить: есть ли в данном случае делитель нуля. Если он найден, то он ставится в итог вместе с соответствующим свидетельством.

isNipotent и HasNipotent суть общие определения того, что такое нильпотент (в кольце), и свойства «кольцо имеет нильпотент». Это определение опирается на функцию возведение в положительную степень в полугруппе.

10. Что ещё есть в библиотеке

Далее, таким же порядком библиотека определяет: кольцо с единицей (RingWithOne), коммутативное кольцо (CommutativeRing), кольцо без делителей нуля (integralRing), евклидово кольцо (EuclideanRing), поле, коммутативный моноид с законом сокращения, моноид с однозначным разложением на множители (UniqueFactorizationMonoid), кольцо с однозначным разложением на множители (UniqueFactorizationRing).

Доказываются формально (на языке Agda) многочисленные леммы об этих структурах — все они известны из учебников и просты с точки зрения математики. Суть этой части разработки состоит в нахождении общего удобного подхода к представлению алгебраических структур.

Пока наиболее сложным оказалось представление понятия кольца с однозначным разложением на множители. Оно опирается на конструкцию моноида ассоциированных классов для моноида ненулевых элементов и на действия над мультимножествами. Потребовалось далёкое расширение библиотеки обработки списков.

Уже реализованным методам и теоремам для евклидовых колец и колец с разложением на множители могут быть посвящены дальнейшие статьи.

11. Безотносительность

В ходе исследования выявилась любопытная практическая черта конструктивной математики: свойство .зависимости от свидетельства, и соответственно, необходимость доказывать безотносительность (irrelevance).

Рассмотрим пример. Поле содержит операцию деления на ненулевой элемент:

- Agda —

1 C = Carrier

divideByNZ : (a b : C) ^ b И 0# ^ RightQuotient setoid _*_ a b

3

4 div : C ^ (b : C) ^ b И 0# ^ C

5 div a b t«0 = proji $ divideByNZ a b t«0

Пусть р , р' : ь - 0# суть два свидетельства неравенства ь нулю. Им соответствуют значения частных: д = а ь р, д' = а ь р'.

Может ли программа пользоваться однозначностью частного — (д

ф д')?

С точки зрения классической математики: ь - 0# есть условие на область определения отображения. Оно может быть либо выполнено, либо не выполнено — булево значение. Если оно выполнено, то итог деления однозначно определён.

Но язык Agda поддерживает конструктивную математику: ь - 0# есть тип всех свидетельств неравенства ь нулю, а их может оказаться бесконечно много. Во-первых, проверяльщик типов в выражении сигнатуры видит формальную зависимость от свидетельства. Во-вторых, в некоторых (других) примерах есть возможность запрограммировать функцию так, что она выдаст разные значения в зависимости от свидетельства.

То есть независимость частного от свидетельства в каждом примере либо не имеет места, либо требует доказательства. И программа, которая пользуется таковой независимостью, должна включать в себя доказательство теоремы независимости.

В данном примере доказательство независимости нетрудно извлечь из определения частного RightQuotient:

Agda —

1 irrel-quot : (a b : C) ^ (p p' : b ^ 0#) ^ div a b p ^ div a b p'

2 irrel-quot a b p p' =

3 let (q , bqiaa) = divideByNZ a b p

4 (q' , bq'iaa) = divideByNZ a b p'

5

6 bq^bq' : b * q ^ b * q'

7 bq^bq' = ^trans bq^a

8

9 q^q' : q ^ q'

10 q^q' = cancelNonzeroLFactor b q q' p bq^bq'

11 in

12 q^q'

То есть из определения частного RightQuotient следует равенство ь * q « ь * q'. Далее, поле наследует из структуры IntegralRing закон отсутствия делителя нуля; из него просто выводится закон сапсешо^егоьрас-ьог сокращения на ненулевой множитель (вывод пропущен). Наконец, равенство q и q' выводится примением последнего закона.

В других случаях подобная теорема независимости не выполнена (это зависит от задания определений в программе). И тогда, если математический смысл требует этой независимости, то её надо добавить как аксиому в одном из полей записи.

Пример: норма |_| в евклидовом кольце должна быть определена на ненулевых элементах. Поэтому библиотека даёт норме второй аргумент: свидетельство неравенства нулю первого аргумента. И оказывается необходимым добавить аксиому независимости нормы:

- Адйа —

^ге!-погт :х:С ^ : х И 0# ^ | х ,, ^ | = | х ,, |

12. Перечень главных технических решений и особенностей

Перечислим описанные выше главные особые приёмы построения библиотеки.

В основу иерархии общих алгебраических структур поставлено множество с алгоритмом разрешения равенства

Каждая общая алгебраическая структура представлена (зависимой) записью (dependent record). Наследование алгебраических структур выражено включением структуры как поля записи или как аргумента записи.

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

Классические алгебраические структуры наделяются некоторыми дополнительными операциями. Это вызвано тем, что практическая алгоритмическая алгебра имеет дополнительные требования по сравнению с классической алгеброй.

Для некоторых операций задан формат Maybe («может быть»). Этот приём применён к тем общим структурам, в некоторых случаях которых для одних операций даны алгоритмы, а для других алгоритмическое решение является проблемой.

Конгруентность алгебраических действий относительно равенства _и_ даётся или выводится в виде явного закона (тогда как в учебниках по математике она подразумевается).

Многие операции имеют свидетельства в качестве некоторых аргументов.

Безотносительность: в некоторых случаях независимость итога функции от выбора свидетельства даётся как закон, в остальных случаях она доказывается (если это существенно).

Свидетельства (доказательства) часто входят в итог функции (операции), и это вносит воспринимаемый компилятором смысл функции. Например, деление выдаёт частное q и свидетельство для решения уравнения (b * q и a).

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

13. Выводы

13.1. Выразительность

На языке Agda алгебраические структуры, алгоритмы и конструктивные доказательства выражаются совершенно адекватно.

13.2. Объём исходной программы

Часть исходной программы, реализующая определения и доказательства, имеет объём текста, не сильно превышающий объем учебника, содержащего соответствующие строгие (в обычном смысле учебного материала) конструктивные доказательства.

13.3. Трудоёмкость построения доказательств

Приведём выдержку из статьи [1]:

"По текущему опыту проекта оказалось, что только трёх приёмов достаточно для построения удовлетворительно выглядящего доказательства:

(1) сведение (normalization),

(2) композиция функций,

(3) рекурсия.

Здесь (1) есть доказательство прямым вычислением (упрощением) к одному выражению, (2) соответствует введению леммы, (3) соответствует доказательству индукцией по построению данного. "

Пусть уже известно конструктивное доказательство того или иного утверждения строгое в обычном смысле учебного материала. Сколько времени может потребовать составление (полного формального) машинно-проверяемого доказательства для системы Agda? С одной стороны, построение машинно-проверяемых доказательств, — на опыте текущего состояния проекта, — очень трудоёмко. В 10 - 20 раз более трудоёмко, чем составление и отладка программы (без полной гарантии правильности) для самого метода вычисления. Это есть плата за верификацию.

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

Что касается возможных разработки и применения каких-то автоматических доказывателей (prover), то в текущем состоянии проекта не видно того участка, на котором их привлечение могло бы существенно облегчить построение доказательств.

13.4. Затраты компиляции

Текущая версия 2.4.2.4 системы Agda берёт для проверки типов в библиотеке DoCon-A примерно в 30 раз больше памяти и времени,

чем было бы естественно. Причина состоит в реализации интерпретатора вычислений на символьных выражениях типов, эта реализации требует улучшения. Этот недостаток интерпретатора скорее всего будет исправлен. Но пока непонятно, какие побочные явления это исправление может принести.

14. Реализация библиотеки

Выпуск 0.03 библиотеки DoCon-A доступен в WWW сети: http://www.botik.ru/pub/local/Mechveliani/docon-A/

В этой статье описана часть опыта разработки следующего выпуска, который, вероятно, появится в 2016 году.

Список литературы

[1] С. Д. Мешвелиани. «О зависимых типах и интуиционизме в программировании математики», Программные системы: теория и приложения, 5:3(21) (2014), с. 27-50, URL: http://psta.psiras.ru/ read/psta2014_3_27-50.pdf -i313,315,316,328,337

[2] А. А. Марков, Проблемы конструктивного направления в математике, Сборник работ. Т. 2: Конструктивный математический анализ, Тр. МИАН СССР, т. 67, Изд-во АН СССР, М.-Л., 1962, с. 8-14. t3i3

[3] P. Martin-Loef. Intuitionistic Type Theory, Bibliopolis, 1984. t3i3

[4] U. Norell, J. Chapman. Dependently Typed Programming in Agda, URL: http: //www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf ^3i3,3i6,3i8

[5] Agda. A dependently typed functional programming language and its system, Homepage of Agda, URL: http://wiki.portal.chalmers.se/ agda/pmwiki.php ^3i3

[6] А. И. Кострикин. Введение в алгебру. Основы алгебры, Наука. Физматлит, М., 1994. t3i6

[7] Дж. Коллинз, Р. Лоос. Компьютерная алгебра. Символьные и алгебраические вычисления, ред. Б. Бухбергер, Мир, М., 1986. t3i6

[8] Дж. Давенпорт, И. Сирэ, Э. Турнье. Компьютерная алгебра, Мир, М., 1991. t3i6

[9] S. D. Mechveliani. "Computer algebra with Haskell: applying functional-categorial-'lazy' programming", International Workshop CAAP-2001 (Dubna, Russia, 2001), pp. 203-211, URL: http://compalg.jinr.ru/ Confs/CAAP_2001/Final/proceedings/proceed.pdft3i6

Рекомендовал к публикации д.ф.-м.н. Н . Н. Непейвода

Об авторе:

Сергей Давидович Мешвелиани

Старший научный сотрудник ИПС РАН. Занимается автоматизацией математических вычислений и рассуждений, функциональным программированием. Автор библиотеки вычислительной алгебры DoCon.

e-mail: mechvel@botik.ru

Пример ссылки на эту публикацию:

С. Д. Мешвелиани. «Программирование основ вычислительной алгебры на языке с зависимыми типами», Программные системы: теория и приложения, 2015, 6:4(27), с. 313-340.

1ЖЬ: http://psta.psiras.ru/read/psta2015_4_313-340.pdf

340

C. MernBe^aaHH

Sergei Meshveliani. Programming basic computer algebra in a language with dependent types.

Abstract. It is described the experience in provable programming of certain classical categories of computational algebra

Key Words and Phrases: constructive mathematics, algebra, dependent types, functional programming, Agda.

References

[1] S.D. Meshveliani. "On dependent types and intuitionism in programming mathematics", Programmnyye sistemy: teoriyaiprilozheniya, 5:3(21) (2014), pp. 2750 (in Russian), URL: http://psta.psiras.ru/read/psta2014_3_27-50.pdf

[2] A. A. Markov, "On constructive mathematics", Problems of the constructive direction in mathematics, Collection of articles. V. 2: Constructive mathematical analysis, Trudy Mat. Inst. Steklov., vol. 67, Acad. Sci. USSR, M.-L., 1962, pp. 8-14 (in Russian).

[3] P. Martin-Loef. Intuitionistic Type Theory, Bibliopolis, 1984.

[4] U. Norell, J. Chapman. Dependently Typed Programming in Agda, URL: http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf

[5] Agda. A dependently typed functional programming language and its system, Homepage of Agda, URL: http://wiki.portal.chalmers.se/agda/pmwiki.php

[6] A. I. Kostrikin. Introduction to Algebra. Fundamentals of algebra, Nauka. Fizmatlit, M., 1994 (in Russian).

[7] R. Albrecht, B. Bukhberger, G. E. Collins, R. Loos (eds.), Computer Algebra: Symbolic and Algebraic Computation, Computing Supplementa, vol. 4, 2nd ed., Springer, 1983, 283 p.

[8] J. H. Davenport, Y. Siret, E. Tournier. Computer Algebra, Seconde edition, Academic Press, 1993, 298 p.

[9] S. D. Mechveliani. "Computer algebra with Haskell: applying functional-categorial-'lazy' programming", International Workshop CAAP-2001 (Dubna, Russia, 2001), pp. 203-211, URL: http://compalg.jinr.ru/Confs/CAAP_2001/Final/ proceedings/proceed.pdf

Sample citation of this publication:

Sergei Meshveliani. "Programming basic computer algebra in a language with dependent types", Program systems: theory and applications, 2015, 6:4(27), pp. 313-340. (In Russian).

URL: http://psta.psiras.ru/read/psta2015_4_313-340.pdf

© S. D. Meshveliani, 2015

© Ailamazyan Program System Institute of RAS, 2015 © Program systems: Theory and Applications, 2015