Текст
                    А. П. ЕРШОВ
ВВЕДЕНИЕ
В ТЕОРЕТИЧЕСКОЕ
ПРОГРАММИРОВАНИЕ
БЕСЕДЫ О МЕТОДЕ
Допущено Министерством
высшего и среднего специального образования СССР
в качестве учебного пособия
для студентов вузов, обучающихся
по специальности «Прикладная математика»
ИЗДАТЕЛЬСТВО «НАУКА»
ГЛАВНАЯ РЕДАКЦИЯ
ФИЗИКО-МАТЕМАТИЧЕСКОЙ ЛИТЕРАТУРЫ
МОСКВА 1977


518 E80 УДК 519.95 Введение в теоретическое программирование (беседы о методе). А. П. Ершов. Главная редакция физико-математической литературы изд-ва «Наука», М., 1977. Книга представляет собой цикл лекций, написанных в виде беседы с читателем. Подробно рассматриваются две, классические задачи теоретического "программирования, решения которых и развитые на этих решениях методы привели к созданию теоретического программирования как самостоятельной математической дисциплины. Это — задача экономии памяти в схемах Лаврова и задача построения полной системы преобразований в схемах Янова. Книга рассчитана на студентов вузов. Андрей Петрович Ершов ВВЕДЕНИЕ В ТЕОРЕТИЧЕСКОЕ ПРОГРАММИРОВАНИЕ (беседы о методе) М., 1977 г., 288 стр. с илл. Редактор Г. Я. Пирогова Технический редактор Е. В. Морозова Корректор Т. С. Вайсберг Сдано в набор 15.07.1977 г. Подписано к печати 17.11.1977 г. Бумага 60χ907ιβ. Физ. печ. л. 18. Условн. печ. л. 18. Уч.-изд. л. 18,48. Тираж 55 000 экз. Т-207И. Цена книги 80 коп. Заказ № 620. Издательство «Наука» Главная редакция физико-математической литературы 11701, Москва, В-71, Ленинский проспект, 15 4-я типография изд-ва «Наука», 630077, Новосибирск, 77, Станиславского, 25 ρ 20204 — ШПо по о» 77 (©Главная редакция Пго/по\ пп "в-оо-01 — ι/ ν^физико-математической ллтератуиь» VOQ(02)-77 издательства «Наука», 1977
ОГЛАВЛЕНИЕ Предисловие 5 Часть I ЭКОНОМИЯ ПАМЯТИ В ОПЕРАТОРНЫХ СХЕМАХ Г л а в а 1. Содержательный анализ задачи 9 §1.1. Краткое повторение программирования 9 § 1.2. Накопление фактов. Линейные программы 14 § 1.3. Накопление фактов. Программы общего вида ч 29 § 1.4. Накопление фактов. Подведение итогов 43 Глава 2. Постановка задачи и общая теория 52 § 2.1. Краткое повторение математических основ 52 § 2.2. Исходные определения 62 § 2.3. Общая теория . . « ♦ 83 Глава 3. Алгоритмизация ♦ « 90 § 3.1. Информационный граф 90 § 3.2. Граф несовместимости 99 § 3.3. Раскраска вершин графа. Общее исследование 110 § 3.4. Раскраска вершин графа. Поиск алгоритма 128 Глава 4. Реализация 143 § 4.1. Вступление 143 § 4.2. Структурированное программирование 145 § 4.3. Общая организация экономии памяти 151 § 4.4. Каноническое распределение памяти 153 § 1.5. Получение графа несовместимости 160 § 4.6. Раскраска вершин графа 164 Глава 5. Заключительный анализ 168 § 5.1. Связке теорией и практикой 168 § 5.2. Исторический обзор 179 Часть II ПРЕОБРАЗОВАНИЯ СХЕМ ЯНОВА Глава 6. Краткое повторение математической логики 189 § 6.1. Логические формулы и булевы функции 189 § 6.2. Алгебра логики 200 § 6.3. Исчисление высказываний 210
4 ОГЛАВЛЕНИЕ Глава 7. Определение схем Янова 22$ § 7.1. Начальные наблюдения 226 § 7.2. Поиск основных определений 239> § 7.3. Эквивалентность схем Янова 245 Глава 8. Исчисление равносильных преобразований 254 § 8.1. Построение исчисления 254 § 8.2. Корректность исчисления 265 § 8.3. Канонические схемы и технические теоремы 270 $ 8.4. Полиота исчисления 276 § 8.5. Еще один исторический обзор 281 Указатель терминов 287
ПРЕДИСЛОВИЕ Для автора эта книга носит экспериментальный характер. Положительным исходом этого эксперимента будет заполнение некоторого пробела в математической литературе. Насколько, однако, актуально заполнение этого пробела, покажет время, а пока автор постарается объяснить предпосылки своего эксперимента. Книга адресована в первую очередь тем, кто изучает математику. Целью математического образования является получение математических знаний и выработка умения применять эти знания либо в решении прикладных задач, либо в строительстве и перестройке самого постоянно развивающегося здания математики. К сожалению, в той части математического образования, которая оцределяется учебными планами и обязательными занятиями, имеет место заметный разрыв между его информационным и творческим компонентами. В значительной степени этот разрыв неизбежен. Большой объем накопленных знаний, впрессованный в учебник или лекционный курс, просто не оставляет времени и места для познания природы и объема творческих усилий, затраченных на добывание этих знаний. Безупречная логика в организации лекционного материала, совершенство в его подаче делают для слушателей незаметными швы и элементы конструкций, создают у студентов ощущение незыблемости идеального; они чувствуют себя скорее посетителями храма науки, нежели его обитателями и тем более строителями. Разделы учебного плана, требующие активной работы студентов (упражнения, практикумы) ^часто носят тренировочный, целевой характер, при котором отсутствует элемент постановки задачи или поиска метода решения, столь необходимый для развития творческого воображения. Общеизвестно, что именно первые три года учебы в вузе являются решающими для формирования профессионального, а зачастую и общего мировоззрения студента. Работа на последних двух курсах носит уже более прагматический, целеустремленный характер. Поэтому так актуальна задача раннего приобщения студентов к творческому началу в выбранной ими специальности. В математическом образовании дополнительной трудностыр
б ПРЕДИСЛОВИЕ является то,что большинство ныне развивающихся разделов математики весьма неэлементарны и не могут быть предметом изучения на младших курсах. Сказанное выше послужило основой для отбора материала и способа его изложения в этой книге. Теоретическое программирование (называемое также в ряде переводных работ теоретической вычислительной наукой или математической теорией вычислений) — это новый раздел математической науки, чьим объектом изучения являются математические абстракции программ — предписаний, выраженных на специальных алгоритмических языках, обладающих определенной информационной и логической структурой и подлежащих выполнению на автоматических вычислительных машинах. Родившись частично из практических потребностей, частично из желания познать природу новых явлений, вызванных электронными вычислительными машинами (ЭВМ), теоретическое программирование, освоив средства и понятия фундаментальных математических дисциплин — логики, теории алгоритмов, алгебры ж комбинаторики, начинает в дополнение к этому постепенно формировать собственный круг понятий и методов. Рассказать о некоторых из них — одна из задач книги, хотя и не главная. Главная цель книги — на примере подробного рассмотрения двух задач, решение которых сыграло очень важную роль в появлении теоретического программирования как предмета, объяснить ход мысли при решении этих задач, продемонстрировать математический метод мышления в действии, внимательно проанализировать этапы содержательного анализа и постановки задачи, раскрыть эстетическую компоненту в пояске решения, другими словами, сделать читателя активным свидетелем процесса получения математического результата. Эта цель предопределила форму изложения: книга написана в виде беседы с читателем и предназначена больше для чтения, нежели изучения. В первой части рассматривается задача экономии памяти в операторных схемах программ. Конструкции и понятия, вошедшие в теоретическое программирование в связи с решением этой задачи, не только внесли существенный вклад в развитие предмета, но и стали основой широкого класса преобразований программ, применяемых в системах автоматизации программирования и при проверке правильности программ. Задача экономии памяти рассматривается как пример решения прикладной задачи с применением математических методов. Изложение разбито на главы, в каждой из которых анализируется один из неотъемлемых этапов полного решения прикладной задачи: содержательная постановка задачи, точная постановка и общая теория, поиски конструктивного метода решения, затем его алгоритмизация и, наконец, составление программ на алгоритмическом язык§>
ПРЕДИСЛОВИЕ 7 Во второй части излагается теория операторных схем Янова — классическая работа, общепризнано послужившая началом математической теории программирования. В созданной А. А. Ляпуновым и Ю. И. Яновым модели программ последний разработал формальное исчисление, в котором полиостью решалась задача распознавания эквивалентности моделей программ и строилась система независимых преобразований программы в любую, ей эквивалентную. Теория операторных схем Янова разбирается в этой книге как методологический пример распространения развитой математической теории (в данном случае формального исчисления высказываний) на новый класс явлений и объектов — операторных схем и их конфигураций. Еще несколько слов в обоснование предмета изложения. Как известно, программирование сейчас становится массовой профессией. К сожалению, как в преподавании программирования, так и в его повседневной практике зачастую преобладает поверхностный, рецептурный подход к его изучению и применению, при котором элементарная грамотность во владении алгоритмическими языками представляется чуть ли не исчерпывающим содержанием профессии. Разрыв между высоким математическим зарядом, получаемым математиками-программистами, и обыденностью рутинной работы по составлению программ создает у некоторых ощущение девальвации их математической квалификации при занятии программированием. Автор надеется, что содержание этой книги поможет практикующим программистам увидеть точки приложения математических методов к объектам и содержанию их деятельности. Другой «удобной» чертой теоретического программирования является то, что эта наука рождается у нас на глазах. Это позволяет более живо и достоверно проследить механизм добывания научных результатов и этапы развития предмета. Одним из признаков молодости науки является преобладание прямых методов доказательств и элементарности постановки многих задач. Это также делает изложение более живым, непосредственным и не требующим высокого порога предварительного знания. Наконец, последним по счету, но не по важности соображением является то, что эта область совпадает с конкретными научными интересами автора, что дает ему возможность излагать материал, полученный из первых рук. Элементарность изложения позволила сделать содержание книги замкнутым и не требующим обязательного предварительного чтения других работ. Тот минимум начального знания, которое все же считается полезным или необходимым, перечисляется или кратко излагается в повторительных параграфах, вставленных в нужных местах. Говоря об элементарности изложения, автор все же должен предупредить читателя, что возможность постигать
8 ПРЕДИСЛОВИЕ содержание книги в темпе чтения будет требовать от него постоянной концентрации внимания и работы мысли. Не ощущая вначале никакого порога и следуя 'линии изложения, читатель тем не менее к концу книги окажется на высоте проблематики, которая является содержанием современной профессиональной математической работы, не делающей никаких скидок на возраст и опыт читателя. Как уже было сказано, книга в основном предназначена для самостоятельного чтения университетскими студентами. Она может быть также использована для кружковой или просеминарской работы в техникумах, физико-математических классах и на младших курсах пединститутов. Материал книги складывался в течение нескольких лет и был частично апробирован в летней школе вузовских преподавателей Дальнего Востока (Владивосток, 1970 г.), в курсе лекций, прочитанных в Стэнфордском университете (1970 г.), и спецкурса для студентов-математиков младших курсов в Новосибирском университете (1971/72 уч. год). Подчеркивая экспериментальный характер этой книги, автор все же не может не назвать некоторые выдающиеся математические сочинения, воодушевлявшие его во время работы над книгой. Надо полагать, многие современные математики испытали на себе воздействие таких замечательных книг, как «Что такое математика?» Куранта и Робинса и «Математика и правдоподобные рассуждения» Пойя. Что каеаётся более избирательного влияния, то в свое время на автора произвели сильное впечатление небольшая книга Хинчина «Три жемчужины теории чисел» как непревзойденный пример раскрытия содержания науки через обсуждение конкретных задач, и известный, мемуар Бэра «О разрывных функциях», убедительно демонстрирующий силу поступательного развития решения задачи, начиная с элементарной постановки и кончая полным решением проблемы во всей ее сложности. Будучи далеким от мысли поставить себя в ряд со столь знаменитыми предшественниками, автор тем не менее видит в своем труде скромную попытку частичного осуществления долга, оставленного нам учителями, — не жалеть усилий на раскрытие пользы, глубины и красоты математической науки перед лицом каждого, желающего приобщиться к этому фундаменту современного знания. Новосибирск, Академгородок А. П. Ершов
ЧАСТЬ I ЭКОНОМИЯ ПАМЯТИ В ОПЕРАТОРНЫХ СХЕМАХ ГЛАВ А 1 СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ § 1.1. Краткое повторение программирования Электронная вычислительная машина. ЭВМ — это автомат, состоящий из памяти и исполнительного устройства. Память состоит из занумерованных подряд ячеек. Номер ячейки называется ее адресом. В ячейках памяти хранится информация, представленная в машине в виде двоичного числа, т. е. последовательности нулей и единиц. Как и в обычной арифметике, позиции двоичных цифр содержимого ячейки называют разрядами. Подобно тому как в азбуке Морзе последовательности точек и тире могут обозначать самую разную информацию, так и нули и единицы в ячейках памяти могут иметь смысл не только двоичных разрядов числа, но и многого" другого. Для того чтобы подчеркнуть возможность самой разной интерпретации содержимого ячеек памяти, это содержимое называют (машинным) словом. Число двоичных разрядов в слове называется его длиной. Исполнительное устройство может выполнять отдельные команды. Набор разных команд (система команд ЭВМ), которые может выполнять устройство, обычно сравнительно невелик, а сами команды очень просты. Типичной командой *является следующая: взять из указанных ячеек памяти одно или два слова в качестве аргументов, передать их в исполнительное устройство, выполнить над ними указанное действие (сложить, умножить, сравнить по величине и т. п.), а результат направить в указанную ячейку памяти. Программа. Из сказанного понятно, что для решения сколько- нибудь сложной задачи ЭВМ должна выполнить очень длинную последовательность команд. Так как ЭВМ работает автоматически, ' то эта последовательность команд должна быть придумана заранее и введена в память машины до начала решения задачи. Обычно в одной ячейке памяти хранится точно одна команда машины, а непрерывность работы исполнительного устройства обеспечивается тем, что каждая команда (если только это не была команда остановки машины) обязательно оставляет в исполнительном устройстве адрес ячейки со следующей подлежащей выполнению командой. Таким образом, составить программу решения задачи на ЭВМ — это значит написать такую последовательность команд машины, чтобы они, оказавшись в нужной части памяти машины
10 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ и выполняясь одна за другой, создали бы последовательность действий исполнительного устройства, которая приведет к решению задачи. Каждая команда программы заставляет выполнить указанное в ней действие с содержимым указанных ячеек памяти. Это значит, что при составлении программы нужно определить, какие ячейки памяти будут использованы в работе машины и что в них будет храниться. Обычно поступают таким образом. Размышляя над способом решения задачи, программист определяет, какие переменные величины появляются и используются при ее решении. Одни величины даются уже в условии задачи — обычно это ее исходные данные и искомые результаты. Другие возникают в ходе решения задачи и называются промежуточными переменными величинами. Их значения вычисляются как результаты выполнения одних команд программы и используются позднее в других командах как их аргументы. Таким образом, при составлении программы у программиста появляется два списка — список команд и список величин программы. Эти списки непосредственно связаны с памятью машины (каждой позиции каждого из списков сопоставляется некоторая ячейка) и друг с другом. Связи величин с командами выглядят следующим образом. Каждая команда состоит из двух частей: кода операции, который указывает, какое действие вызывает команда, и адресной части. В адресной части указаны адреса ячеек, используемых в качестве аргументов и результатов команды. В некоторых командах в адресной части указываются не ячейки с величинами программы, а адреса команд,— в частности, когда следующая по порядку выполнения команда находится в программе не вслед за данной, а где-то в другом месте, которое и указывается своим адресом. Это случается, например, при необходимости повторить группу команд программы несколько раз или выбрать один из нескольких вариантов вычислений в зависимости от значения переменных величин программы. Программирование. Осмысливая только что прочитанное, мы можем усмотреть некоторое сходство программирования для ЭВМ со школьным способом решения арифметических задач по вопросам. Решая задачу таким способом, ученик должен был составить* план решения в виде серии вопросов. В вопросе спрашивалось, какая величина задачи должна быть вычислена. Вопрос ставился так, чтобы это вычисление выполнялось за одно действие над уже известными величинами. Пределом трудности считалась задача, которая решалась в 5 — 6 действий. Программирование же для ЭВМ реальных задач требует предусматривать в плане решения десятки тысяч и большее количество действий, для каждого из которых должна быть безошибочно записана вызывающая его команда. Поэтому с самого начала появления ЭВМ все усилия
§ 1.1. КРАТКОЕ ПОВТОРЕНИЕ ПРОГРАММИРОВАНИЯ Ц программистов были направлены на создание методов облегчения задачи программирования. Один из таких методов состоит в том, что составление программы для ЭВМ разбивается на этапы. На одном этапе программист составляет программу в такой форме, в которой ему легче эту программу придумать. На другом этапе промежуточная форма программы по некоторым формальным правилам превращается в программу, непосредственно воспринимаемую машиной (машинную программу). Формальными эти правила являются в том смысле, что их применение к промежуточной форме требует педантичной точности, но не требует понимания того, что делает программа. Другими словами, эти правила единым образом применимы к любой промежуточной форме программы. Последнее обстоятельство позволяет правила перевода промежуточной формы программы в машинную описать в виде общего алгоритма. Этот алгоритм можно в свою очередь запрограммировать. У получившейся таким образом «сверхпрограммы» входными данными будет любая промежуточная форма программы, а результатом — машинная программа, в точности соответствующая промежуточной форме. В специальной литературе такие «сверхпрограммы»- переводчики называются трансляторами, компиляторами или программирующими программами. При наличии транслятора промежуточная форма программы, бдлее удобная для ее составления человеком, становится для него окончательной формойг а всю остальную работу по освоению программы машина с помощью транслятора берет на себя. Таким образом, задача программирования как научно-технической дисциплины состоит в том, чтобы разрабатывать «языки программирования» — способы выражения программ, удобные для человека, и методы трансляции, перевода с языков программирования на то, что можно назвать языком машины или машинным языком. Символическая программа. Простейшая помощь программисту состоит в том, чтобы предоставить ему возможность составлять вместо машинной так называемую символическую программу. Символическую программу программист придумывает, тоже держа в голове систему команд ЭВМ. Он по-прежнему должен написать список команд и список величин программы так, чтобы каждая позиция в этих списках соответствовала одной ячейке памяти машины. Однако способ записи этих списков более удобен для программиста. Вхместо адресов ячеек памяти для величин программы он может использовать те естественные обозначения, которые эти величины имели в условии задачи, или те, которые он сам придумает для большей наглядности. Вместо числового кода операции, изображаемого в машинной команде комбинацией двоичных цифр, программист может использовать так называемый
12 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ мнемонический код (мнемокод), который своим видом подсказывает ему содержательный смысл команды: например, + для команды сложения, ^ для команды сравнения чисел, или слово СТОП для команды остановки машины. Если программисту нужно употребить адрес команды, он помещает в символической программе против этой команды любое подходящее по смыслу слово или букву, которая называется меткой команды, и употребляет в адресной части эту метку в качестве адреса команды. Для обозначений величин, мнемокодов и меток программист может использовать любые символы, буквы и цифры, лишь бы получающийся текст символической программы годился для ввода в ЭВМ. В первом приближении достаточно сказать, что в ЭВМ можно ввести любой текст, который может быть напечатан на пишущей машинке без особых ухищрений, т. е. без выхода за основную строку, без подчеркиваний и надпечаток. Преобразование или, как принято говорить, трансляция символической программы в машинную происходит следующим образом. Сначала ЭВМ под управлением транслятора воспринимает символическую программу. Затем машина составляет таблицу обозначений и меток, использованных в программе. Таблицу мнемокодов машине составлять не надо, так как она одна и та же для всех символических программ и хранится в трансляторе постоянно. После этого происходит распределение памяти, т. е. сопоставление каждой величине и каждой команде программы той ячейки памяти, в которой эта величина или команда будет находиться. Заметим, что память можно распределять тривиально: а) для команд: размещать команды машинной программы в точности так, как они размещены в символической программе. Тогда достаточно посчитать число команд в программе, отметить в памяти машины такое же количество ячеек, начинающихся с некоторого адреса А, и сопоставить п-& по порядку команде ячейку с адресом А + η — 1; б) для величин: каждую величину помещать в отдельную ячейку; всего будет занято столько ячеек памяти, сколько обозначений величин использовано в символической программе. После распределения памяти остается систематически в каждой команде символической программы заменить мнемокод операции на двоичный код, а обозначения величин и метки команд в адресных частях команд — на сопоставленные им адреса ячеек. Алгоритмический язык. Следующим серьезным шагом в сторону облегчения работы программиста является программирование на алгоритмических языках. Программа на алгоритмическом языке тоже состоит из списка команд и списка величин программы. Однако эти команды на-
§ 1.1. КРАТКОЕ ПОВТОРЕНИЕ ПРОГРАММИРОВАНИЯ 13 столько не похожи на команды машины, что они даже и называются по-другому — операторами. Величины программы тоже могут не иметь прямого отношения к ячейкам памяти машины. Например, программист может использовать в программе комплексные числа и не заставлять себя каждый раз вспоминать, как они изображаются в памяти машины. Основным оператором алгоритмических языков является вычисление по формуле. Вычисленное значение может быть присвоено переменной величине или использовано каким-либо другим образом, разрешаемым правилами языка. Операции, используемые в формулах, являются либо общеизвестными математическими операциями и функциями, либо объясняются правилами языка, либо придумываются самим программистом. Естественно, что в последнем случае программист должен с помощью подходящей ^вычислительной процедуры «описать», как выполняется соответствующая операция или функция. Формулы в алгоритмических языках называются выражениями, а соответствующие операторы — операторами присваивания, или арифметическими операторами. Кроме указанных операторов, в алгоритмических языках используются своего рода «организующие» операторы, которые не столько вычисляют, сколько определяют порядок вычислений. К ним относятся условные операторы, которые выбирают тот или иной вариант вычислений, в зависимости от проверки некоторого условия, и операторы цикла, которые организуют повторение некоторых вычислений нужное число раз. Наконец, программы на алгоритмических языках не записываются в жестком табличном формате, как машинные и символические программы, а имеют фразовую структуру, к тому же использующую, правда, в сравнительно ограниченных пределах, такие общепонятные слова (или их сокращения), как начало, конец, целый, вещественный, цикл, процедура, если, то, иначе и т. п. Все это вместе взятое приближает алгоритмические языки как к естественным человеческим языкам, так и к общепринятой математической символике. Алгол. В нашей книге мы буцем повсеместно использовать один из наиболее распространенных алгоритмических языков — алгол-60. Для начинающих читателей можно мимоходом заметить, что говорить «алгоритмический язык алгол» — это, примерно, то же самое, что говорить «черные чернила», так как оригинальное название языка ALGOL есть сокращение от ALGOrithmic Language, что является английским эквивалентом «алгоритмического языка». Если же указанную категорию читателей больше беспокоит то, что им еще не представился случай познакомиться с этим языком, то им автор рекомендует для предварительного чтения книгу А. Л. Брудно, Алгол, М., «Наука», 1971.
14 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ Трансляция программ, составленных на алгоритмическом языке, в машинные уже существенно более сложна, чем в случае символических программ. Минимальная работа состоит в следующем. Транслятор тоже начинает с того, что составляет таблицу символических имен, использованных в программе для величин программы, меток операторов и функций, придуманных программистом. После этого формулы, использованные в записи программы, расчленяются на отдельные операции и функции. При этом в программе появляются новые промежуточные величины. Обозначения функций, введенных программистом, заменяются ссылками на вычисляющие их процедуры. После этого каждая элементарная операция или функция, упоминаемая в программе, заменяется последовательностью машинных команд, которые, как принято говорить, реализуют эту операцию или функцию. Это же происходит и с «организационными» условными операторами и операторами цикла. Соответствие между элехментарными действиями, функциями и операторами алгоритмического языка и реализующими их «кусочками» машинной программы является постоянным и закладывается в транслятор. В результате сборки этих «кусочков» получается символическая программа, для которой затем производится уже упоминавшееся нами распределение памяти. Именно этот процесс распределения памяти и будет для нас главным предметом обсуждения в первой части книги. Прежде чем приступить к делу, сделаем, однако, одно техническое замечание. Пусть программа на алгоритмическом языка написана так, что каждый оператор в ней содержит только одну операцию. Тогда, если операция алгоритмического языка можег быть выполнена одной командой ЭВМ, а каждая величина программы может поместиться в одной ячейке памяти, то соответствие между программой на алгоритмическом языке и реализующей ее символической програмх\юй становится буквальным: отличие между ними только в способе записи. Это позволит нам в книге пользоваться только алголом, даже если мы будем работать с примерами, по своей детальности приближающемся к символическим программам. § 1.2. Накопление фактов. Линейные программы Простейшие примеры. Вообразим себя начинающими програм-. мистами, которым надо вычислить на ЭВМ у = я7, не используя операцию возведения в степень. Прочитав повторительный параграф по программированию, воспользовавшись нужными правилами алгола и мобилизовав, школьный опыт решения задач по вопросам, мы можем написать следующую программу:
§ 1.2. НАКОПЛЕНИЕ ФАКТОВ. ЛИНЕЙНЫЕ ПРОГРАММЫ Д5 Ή ρ и м е ρ 1. Вычислить х1. начало вещ х, у, х2, хЪ> х4, хЪ, #6; ввод (х); х2: = хЗ :== xi : = хЪ : = хб : = »: = вывод (у) X х2 хЪ х4 хЪ xQ X X X X X X х\ X] х\ х\ х\ х; Однако не менее вероятно, что программа будет выглядеть также и следующим образом: Пример 2. Вычислить х1. начало вещ х, у; ввод (х); У У У 11 У У вывод ([ конец , — X /\ Х'у = У X х\ = у X х; = у х χ; = У х х\ = у х *; /) Эти два простейших примера уже дают нам пищу для размышления. Во-первых, мы видим, что обе программы решают нашу задачу. Во-вторых, вторая программа гораздо лучше первой: она требует только двух ячеек памяти, в ней пять последних команд одинаковы, и это наталкивает нас па еще большее сокращение программы, если заставить (с помощью оператора цикла) один оператор у: = у Χ χ повториться пять раз: Пример 3. Вычислить х7. начало вещ х, у; цел i\ ввод (х); у : = χ Χ х\ для i : = 1 шаг 1 до 5 цикл у := у χ χ; вывод (у) конец Первый вывод. Задача может быть запрограммирована разными способами: одни способы лучше, другие хуже.
16 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ Второй вывод. Программы могут отличаться друг от друга сильнее и слабее: первая и вторая программы больше похожи друг на друга, нежели каждая из них на третью. Третий вывод. Первые две программы настолько похожи, что даже лучше говорить, что это одна и та же лрограмма, только с разными обозначениями для промежуточных величин — в первой программе они все разные, а во второй одни и те же. Четвертый вывод. Имеет смысл такая проблема: составить программу, используя наименьшее количество обозначений для величин. Это приводит к экономии памяти. Следует заметить, однако, что все эти выводы носят чисто наблюдательный характер. Автору первой программы не мешало бы спросить у своего коллеги, составившего вторую программу: «А как ты додумался весь счет вести через ι/?» Если второй автор не глуп, он не выразит недоумения, а, подумав, ответит: «Как только у умножается на х, он мне уже не нужен, и поэтому я могу это произведение направить туда же». В свою очередь первый автор, чтобы оправдать свой подход, скажет: «Но ведь у меня программа логичнее: χ в пятой степени, например, никогда не будет равен χ в третьей, вот я их и обозначил по-разному». Второй заметит: «Но зато я зациклил и тем самым сократил свою программу»,— и покажет первому третий пример. Если кому-либо такая подача материала покажется слищком примитивной, то мы заметим, что дискуссия двух авторов списана с реальных занятий по программированию, а в каждом из трех высказываний содержатся зерна истины, развитие которых постепенно приведет нас к решению задачи. В частности, мы немедленно попробуем обобщить сделанные замечания авторов программ в виде некоторых отправных принципов. А. При сочинении программы мы из соображений удобства и логичности вводим различные обозначения для исходных и промежуточных величин задачи и для ее результатов. Если после получения символической программы распределить память по принципу «каждой величине свою ячейку», то может оказаться, что памяти будет израсходовано больше, чем это «на самом деле» нужно. Этот факт можно выразить и по-другому: можно переписать программу так, что она будет решать ту же задачу, но содержать меньшее количество обозначений. Б. Сокращать число велр1чин программы можно следующим образом: имея в команде (или операторе) некоторый результат, не надо торопиться вводить для него новое обозначение, а посмотреть, нет ли в данный момент «свободной» величины, т. е. такой, текущее значение которой больше не потребуется. Если такая величина есть, то она и берется в качестве обозначения результата. Новые примеры. Рассмотрим еще некоторое количество примеров. Пусть надо вычислить у = я59, опять-таки, не используя
§ i 2. НАКОПЛЕНИЕ ФАКТОВ. ЛИНЕЙНЫЕ ПРОГРАММЫ tf операцию возведения в степень. Конечно, имея перед глазами пример 3, уже никому не захочется писать подряд 58 команд умножения, так что первый подход даст нам Пример 4. Вычислить я59. начало вещ х, у, цел ί; ввод (х); у: = хХх; для ί: = 1 шаг 1 до 57 цикл у := уХх; вывод (у) конец Однако эта программа, будучи весьма короткой, тем не менее очень долго работает: на решение задачи расходуется по меньшей мере 3x57 действий: умножение, изменение i и сравнение его с 57. В то же время, если бы надо было вычислить 264 (64 = 26), то на это потребовалось бы всего 6 умножений: У У У У ■ У- У ■ := хХх := УХУ := УХУ = уху = уху = уху (χ2), (X4), (*"), (*16), (х32), (*«)· Однако это нарастание степеней * двойки в геометрической прогрессии поможет нам и в нашем случае. (А заинтересованный читатель без труда теперь додумается до правила для любого целого показателя степени.) Представим 59 как сумму степеней двойки: 59 = 32 -f-16 -f- 8 + 2 + 1 .{Тогда программу организуем так: вычислим подряд и сохраним значения степеней χ с показателями, равными степеням двойки, так чтобы последняя степень двойки была бы еще меньше исходного показателя, а следующая — уже больше. А потом перемножим друг на друга те степени х, у которых значения показателей входят как слагаемые в представление исходного показателя: ХЪ9 = χΜχχΜχχ*Χχ*χΧβ В результате получаем Пример 5. Вычислить хъо. начало вещ #, у, х2, χί, χ8, х16, #32; ввод (х); Х£ . — X /\ Д/, х4 := х2Хх2\ х8 := хАхх4; χίβ := я8хя8; *32 := ИбхИб;
18 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ у :== хХх2; у := уХх8; у := yXxlft; у := уХ#32; вывод (г/) конец В заключительной части программы мы, иод влиянием опыта 1-го и 2-го примеров, уже «вели вычисление через ι/», экономя обозначения промежуточных величин. Однако принцип Б побуждает нас более внимательно проверить программу и спросить себя, везде ли мы вводили новые величины «по необходимости», а не по инерции начальной идеи вычисления #59? Наше рассуждение звучит примерно следующим образом. Занумеруем операторы программы: 1: х2: = хХх; 2: #4: = #2 χ #2; 3: х8: = хАххА; 4: #16: = #8х#8; 5: #32: = #16х#16; 6: у:= хХх2; 7: у: = ухх8; 8: у:= yXxlft; 9: у:=ух32. Результат оператора 1 мы не можем присвоить #, так как тогда новый χ будет равен #2, а нам нужен исходный χ в операторе 6. Результат оператора 2 мы не можем присвоить ни #, ни х2 по той же причине. Однако после выполнения команды 3 нам уже не нужна величина #4 и мы можем ее результат присвоить той же переменной, заменив, естественно, х8 в командах 4 и 7 на #4. Просмотрев программу до конца, мы видим, что это единственная экономия на величинах, которую мы можем здесь себе позволить. Пример 6. Вычислить #59. начало вещ #, у, #2, #4, #16, #32; ввод (х); ΧΔ . —= X /\ Ху #4:= #2х#2; #4: = хАХхА; #16:= #4 χ #4; #32:= #16х#16; у:= хХх2; у:= yxxi;
§ 1.2. НАКОПЛЕНИЕ ФАКТОВ. ЛИНЕЙНЫЕ ПРОГРАММЫ 1£ у: = г/χ #16; у: = уХх32; вывод (у) конец Наши кропотливые рассуждения о невозможности сэкономить обозначение величины во всех пяти первых операторах, кромо 3-го, позволяют нам, однако, догадаться о причине этой невозможности: мы плохо организовали нашу программу Мы сначала посчитали все «степени двойки», а только после этого начинаем их использовать. Поступим по-другому: получив очередную «степень двойки», мы ее тут же «вгоним» в у, если она является слагаемым нашего показателя. Если же нет, то мы только употребим ее на получение следующей «степени двойки». Одновременно стараемся соблюдать принцип Б. Получаем Пример 7. Вычислить хЪ9. начало вещ х, у, х2\ ввод (х); χδ :== χ χ Ху у: = хХх2; х: = .г2х.г2; Х\== Χ X Х\ у\= уХх\ х:= хХх у:= ухх; X. — X X X) у:= уХх; вывод (у) конец Этот результат удовлетворит всякого, но вы, читатель, не будете настоящим исследователем, если не спросите себя, а нельзя ли обойтись меньшим количеством величин? Утвердительный: ответ, по-видимому, будет небольшим открытием для большинства; Π ρ и λΐ е ρ 8. Вычислить я59. начало вещ х, у; ввод (χ); У X У У X У X. — X X Ху = хху; = уху; ■= уху; = хху; = уху; = хху;
20 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ #:= уху; у: = хХу; вывод (у) конец Тем, кто не додумался до этого примера, автор рекомендует в качестве «утешительного забега» доказать, почему в этой программе нельзя обойтись меньшим количеством величин, т. е. одной. Пауза для размышления. После этих восьми примеров мы накопили достаточно материала, чтобы в нем разобраться, прежде чем двинуться дальше. Во-первых, мы окончательно поняли, что число обозначений величин в программе и число ячеек памяти — это непосредственно связанные друг с другом характеристики программы. Нет никакой принципиальной разницы между переменной величиной программы в алгоритмическом языке и ячейкой памяти машинной программы. Пока мы заняты построением программы, мы можем эти понятия отождествлять, й" это нам действительно удобнее для рассуждения. Величина в программе — это не столько какая-нибудь физическая или математическая переменная величина, проникшая в программу из исходной формулировки задачи, сколько в чистом виде элемент памяти, своеобразная камера хранения. В такой камере хранения хранится некоторое значение. Поступить туда оно может только как результат некоторого оператора или команды. Старое значение переменной величины при этом перестает существовать. Каждое значение в разумно составленной программе вырабатывается для того, чтобы позднее быть использованным в качестве аргумента в каком-то месте программы. Пока оно еще не использовано, хранящая его переменная величина «неприкосновенна» и ей нельзя присваивать нового значения. Таким образом, сколько величин используются в разных вариантах программы и как они обозначаются — не столь существенно, как то, что они должны сохранять все информационные связи в программе, т. е. «передачи» значений от результатов одних операторов к аргументам других. Второй вывод состоит в том,-что существуют различные способы построения вариантов программы, как-то влияющих на количество величии в программе и их обозначения. Первый способ состоит в том, что мы имеем, по существу, одну и ту же программу с различными наборами величин. Программа одна и та же в том смысле, что она состоит из одних и тех же команд с одними и теми же зависимостями аргументов одних операторов от результатов других (примеры 1 и 2, 5 и 6, 7 и 8). Выигрываем мы на том, что согласно принципу Б мы не заводим без нужды новые величины, а стараемся обходиться уже имеющимися. Второй способ сохраняет состав команд и зависимости между результатахми и аргументами, но
§ 1.2. НАКОПЛЕНИЕ ФАКТОВ. ЛИНЕЙНЫЕ ПРОГРАММЫ 21 разрешает перестраивать команды в программе, если это помогает делу (примеры 6 и 7). В природе экономии памяти в этом способе мы, скорее всего, еще не разобрались, не считая несколько расплывчатого утверждения, что если организовывать вычисления так, чтобы использовать результат по возможности сразу после получения, то можно сократить потребность в памяти для хранения значений. Наконец, третий способ дает эффект благодаря полной перестройке программы, при этом, в общем случае, экономится память не для величин (в примере 3 мы даже ввели еще одну величину Ϊ), а для программы, которая благодаря циклу становится более короткой. Первый способ, однако, в каком-то смысле является самым основным: каким бы способом мы ни получили программу, если мы хотим получить максимальную экономию памяти, мы должны проверить, не содержит ли она лишних величин, и постараться найти наилучший вариант (как в случае примера 8). Наконец, мы должны отдавать себе отчет, что мы еще очень далеки от решения общей задачи экономии памяти* У нас в запасе «есть только один принцип Б в качестве рабочего правила, а все наши примеры исчерпываются простейшим видом программ, так называемыми линейными программами, т. е. программами, не содержащими ни условных операторов, ни циклов, ни ссылок на процедуры вычисления функций (примеры 3 и 4 не в счет, так как мы их не анализировали). При этом даже для линейных программ принцип Б еще не носит характера формального правила и требует дальнейшей проработки, чем мы и займемся. Информационные связи и сечения. Поразмышляем еще раз над принципом Б в попытках превратить его в систематическую процедуру: «не надо торопиться вводить для результата новое обозначение, а посмотреть, нет ли в данный момент освобождающейся величины, т. е. такой, текущее значение которой больше не потребуется». Эти слова подсказывают нам, что мы, решая задачу экономии памяти, должны просмотреть операторы программы в порядке их выполнения. Тогда (в случае линейной программы, записанной в столбик) выше очередного просматриваемого нами оператора будут операторы уже выполнившиеся, для которых мы уже как-то распорядились выбором величин, и ниже будут команды, еще не выполнившиеся. Мы не торопимся ввести новую ьеличину для результата очередного оператора 5, а смотрим на величины, обозначающие результаты операторов, стоящих выше. Что значит, что величина ν, которая была результатом оператора R, еще не освободилась? Это значит, что ниже оператора S есть еще один оператор, Г, имеющий ν своим аргументом. Достаточно ли точное это определение? Легко можно догадаться, что нет. Путем комбинирования возможных случаев получим такие варианты выработки и использования величины ν по отношению к оператору S
22 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧР1 (для четкости будем полагать, что никаких других использований величины ν, кроме явно показанных, в программе нет): Программа Программа Программа Программа R: ν :=... S: χ :-—... Τ: ζ := F(v) R: ν :=... Τ': ζ := F'{v) S: χ :—... Τ: ζ := F(o) Β: ν :=... Τ': ζ := *"(ι?) Λ" : χ :—... Τ: ζ := /» 7?: ν :=... Τ": 2 := F» iS*: ж := случай а) случай б) Случай в) случай г) Посмотрев на эти картинки, мы заключаем, что единственным условием того, что величина ν занята по отношению к оператору Sr является такая ситуация, что S находится между (в смысле положения в программе) выработкой ν (оператор R) и использованием ν (оператор Г);,при этом между S и Τ нет оператора, вырабатывающего v. Получается, что оператор S стоит как бы на пути передачи значения от R к Т. Эту ситуацию можно сделать более наглядной, если изобразить этот путь величины ν в виде линии, соединяющей результат оператора R и аргумент оператора Τι Я: Г: -Ж»)) Если допустить, что в нашей программе таким образом обозначены все пути передачи значений от результатов к аргументам, то принцип Б*сильно упрощается: для оператора S занятыми являются все величины, пути которых «пересекают» этот оператор» Не поленимся нарисовать эту картинку (рис. 1.1) для какого- нибудь из наших примеров, хотя бы пятого (сразу соображаем, что χ для оператора ввода является результатом, а у для оператора вывода — аргументом). Программа выглядит более громоздкой, но в то же время для наших целей необычайно ясной. Мы проложили по ней все пути передачи значений величин — от результатов к аргументам. Давайте сразу их назовем информационными связями между аргументами и результатами операторов. Все эти связи ориентированы «вдоль» по направлению выполнения программы. Аналиа этих связей дает нам полное представление о том, как надо распределять память в программе. Действительно, подчеркнем мысленно каждый оператор горизонтальной линией, которая будет отмечать момент выполнения этого оператора. Назовем эту линию сечением программы. Тогда число информационных связей, пере-
§ 1.2. НАКОПЛЕНИЕ ФАКТОВ. ЛИНЕЙНЫЕ ПРОГРАММЫ 23 секаемых сечением, показывает нам, сколько величин в настоящий момент «занято», т. е. используются для хранения результатов, которые выработаны раньше, но потребуются позднее, а символы величин, сопоставленных концевым точкам этих «маршрутов», указывают, какие конкретно величины используются. качало вещественные двод x,y,xZ,x4, х8,х16у xoZl ■@ <ε> <д <д <д = 0X0 = <£> = © конец быбод [(у X X X я) X © © И) X {xt ъ а) х \$а у) X \х16) у) X Ш Рис. 1.1. Программа с проложенными информационными связями. Последнее наблюдение немедленно подсказывает нам систематическую процедуру переобозначения величин программы, дающую наименьшее количество обозначений· Чтобы подчеркнуть ее
24 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ. систематичность, мы намеренно выберем совсем другие обозначения: Й, t2 и т. д. Процедура экономии памяти в линейных программах? 1. Начальный шаг: берем первый оператор. Он содержит только результат, которому сопоставляется величина ti. Имя этой же величины сопоставляется всем аргументам операторов, к которым ведут от этого результата информационные связи. 2. Очередной шаг: берем очередной оператор 5 ν Пусть к этому времени уже использованы некоторые величины. Из этого набора, отбрасываем занятые величины, т. е. величины, информационные связи которых пересекаются сечением оператора S. Если в наборе останутся величины, выбираем из них любую (например, с наименьшим номером) и сопоставляем ее результату оператора S* Если все использованные величины «заняты», добавляем к ним еще одну, которую и сопоставляем результату. Имя величины, сопоставленной результату оператора S, сопоставляем всем аргументам операторов, к которым ведут от этого результата информационные связи. Очевидно, что если для каждого аргумента есть задающий его результат, то все величины программы получат новые имена; при этом их будет всего ровно столько, какова максимальная ширина сечений программы, т. е. максимальное количество промежуточных значений величин, которые нужно хранить в какой-либо момент выполнения программы. Действительно, согласно процедуре мы добавляем к списку использованных величин новую только тогда, когда все величины заняты, а нам надо увеличить текущую ширину на единицу добавлением новой информационной связи. Применив эту процедуру к рис. 1.1, мы получим следующую* программу: начало вещ ti, t2, t3 ввод (ti); t2: t3: t3 Й: *5: ti: ti: ti ti = tixtl; = t2xt2; := t3xt3; = ί3χβ; = tAxtA; = tlx t2; = ti X t'S; = tlXtA; = *lx*5: вывод (ti) конец Только что полученная процедура является серьезным шагом: вперед. Мало того, у нас уже зреет убежденность, что она пол-
§ 1.2. НАКОПЛЕНИЕ ФАКТОВ. ЛИНЕЙНЫЕ ПРОГРАММЫ 25 тюстью решает вопрос об экономии памяти в линейных программах. Это побуждает нас продолжить ее анализ. Операторная схема. Возможно, кое-кто из читателей уже обратил внимание на то, что после того как мы построили информационные связи программы, исходные имена величин, употребленных в ней, нам уже не нужны. Мало того, они нам даже мешают, £>): О О О О Ό О О О О -О ^6 ^~6 •6 =Ъ =ъ =ъ ^ъ ъ X X X X X X ъ ъ δ Ъ = ό*ό ъ ъ Рис. 1.2. Информационные связи делают имена величин ненужными. «загораживая» те места, в которых мы должны согласно процедуре проставлять имена новых величин. Нам будет приятнее работать с программой без величин — только с кружками, отмечающими места аргументов и результатов операторов (рис. 1.2).
26 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ При взгляде на это графическое изображение программы нам: начинает бросаться в глаза неуместность алголовской стилистики и прочей информации о программе, которая была неотъемлемой частью при составлении программы, но становится не столь существенной при решении нашей специальной задачи об экономии памяти. Мы уже распрощались со списком описаний величин, да и с самими величинами после того, как они сослужили свою службу в построении информационных связей. Что же нам нужно по существу? Нам нужно знать, что операторы образуют линейный порядок. Для каждого оператора нам нужно знать, сколько у него аргументов и результатов (оператор ввода, например, может иметь несколько результатов). Нам совсем не важно, какую функцию выполняет оператор. Другими словами, нам достаточно знать не саму программу, а только ее схему, в которой были бы только обозначения операторов, а не их содержание, был бы указан порядок их выполнения, были бы как-то отмечены их аргументы и результаты, притом так, чтобы было удобно изображать их информационные связи и подписывать к ним имена величин. При всем: при этом мы уже оценили полезность графического представления такой, как ее естественно назвать, операторной схемы. Оставляя чргтателя в неведении относительно множества картинок, перерисованных разными авторами в поисках наглядности, мы сразу предложим ему операторную схему нашей программы в уже общепринятом графическом оформлении (рис. 1.3). Прямоугольниками изображены операторы. Их обозначения: ставятся внутри. Жирные стрелки указывают на порядок выполнения операторов. Маленькие кружки на отросточках — аргументы и результаты. Отростки, идущие по ходу стрелок,— результат, а напротив — аргументы. Имена величин, сопоставленные аргументам и результатам, пишутся рядом с кружочками (рис. 1.3Г а). Пунктирные стрелки — информационные связи. Чтобы не загромождать чертежи (рис. 1.3, б), там, где это удобно, пунктирные стрелки, идущие от одного результата, сливаются в одну связку. Такое графическое сокращение даже удобно по существу: если подсчитывать ширину сечения, нужно все стрелки, идущие от одного результата, считать за одну, т. е. как раз считать связками. На этом чертеже информационные связи нарисованы с «вывертами» — не по кратчайшему расстоянию,— для того, чтобы более четко показать ширину информационных связей. Графическое представление схемы программы и ее информационных связей делает гораздо более понятным эффект перестановки операторов программы в примере 7 (рис. 1.3, в): сократив, маршруты передачи значений от результатов к аргументам, мы разгрузили информационные связи и сократили их ширину до· двух, что, кстати, в отличие от программы примера 7, видно на ©той схеме с очевидностью.
§ 1.2. НАКОПЛЕНИЕ ФАКТОВ. ЛИНЕЙНЫЕ ПРОГРАММЫ 27 1 А | χ б f p<2 1 в | х'1б [ p x2 Li ' <ζ·4 <* 1 о xb [J^J < px8 f^j 2,16 о ' f 0_X16 Г- I I А I χ Q { 9zl I га ! J/ S ^ \ о x8 L/ I ! A Ρ Ч \oXf6 \ ι/_j ι ox32 I 7 I I A | г-* Ь II в I b im 'ТУШ !!l·^ I TfTi ь ! Η b ! 11 ira 1 1 ^SJ r* ! I 1 £ 1 L > 1 X*<\ ] ;? ! 1 # 1 1 r^T 1 l· :? I / 1 4 J ■*? m Г r I иг | j_/r ] a) S) δ) Рис. 1.3. Операторные схемы, а) Пример 5. б) Информационные связи примеров 5 и 6. в) Информационные связи примеров 7 и 8.
28 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ Связки. Ширина сечений. Похоже, что мы уже исчерпали все? полезные факты, которые нам могут дать линейные программы. Главными нашими достижениями являются открытие важности анализа информационных связей программы, а также извлечение из программы тех и только тех ее характеристик, которые нам^ помогают в решении задачи экономии памяти и которые изображаются в виде ее операторной схемы. После того как мы уже несколько освоились с этой находкой, давайте разберем подробнее, что такое информационная связь, как мы ее находим по заданной программе и как используем для распределения памяти. Мы прокладываем связь от результата оператора S к аргументу оператора Г, если S имеет своим результатом некоторую величину хл Τ имеет χ своим аргументом, Τ выполняется позже S, т. е. от S к Τ ведет цепочка операторов, и, наконец, в этой цепочке ни один из операторов не имеет χ своим результатом. Для построения информационных связей и вообще, для решения задачи экономии: памяти, нам достаточно иметь операторную схему программы, в которой указаны символы операторов, их аргументы, результаты и сопоставленные им имена величин, а также порядок выполнения операторов. После построения всех информационных связей программы исходное распределение памяти нам уже не нужно. Мало тогог по совокупности информационных связей мы можем построить любое другое распределение памяти в данной программе, в том числе и самое экошшное по числу использованных величин. Информационные связи в операторной схеме группируются в связки. В одну связку входят все информационные связи, выходящие из некоторого результата. Для правильного распределения памяти нужно, чтобы всем аргументам и результату, входящим: в связку, была бы сопоставлена одна и та же величина. Самое неэкономное распределение памяти получается, когда каждому результату, или, что то же самое, каждой связке сопоставляется своя величина. Экономия памяти достигается тогда, когда нескольким связкам сопоставляется одна и та же величина. Однако чтобы не нарушить информационные связи, нельзя сопоставлять одну и ту же величину конкурирующим информационным связям. В линейной программе конкурирующими являются те и только те связки, которые одновременно пересекаются каким-либо сечением ее операторной схемы. Для линейной программы есть простой алгоритм нахождения экономного распределения памяти. Число- используемых величин при этом оказывается равным ширине^ сечений, т. е. максимальному числу связок, рассекаемых сечениями. Эти выводы мы теперь примем в качестве рабочих гипотез, которые будем проверять на более разнообразных примерах в поисках новых фактов. Очевидно, что прежде всего нам надо усложнить структуру программ.
§ 1.3. НАКОПЛЕНИЕ ФАКТОВ ПРОГРАММЫ ОБЩЕГО ВИДА 29 § 1.3. Накопление фактов. Программы общего вида Программа с условиями. Пример 9. Решить квадратное уравнение ах2 + Ьх + с = О для общего случая. Комплексное решение представить в виде значений модуля и аргумента комплексно сопряженных корней. Представив общую формулу решения — Ь ± УЪ2 — 4ас #1,2 = 2а Ь У\ б2 — Аас | в виде ρ = —γ- и q = π » мы затем в зависимости or знака дискриминанта Ъ2 — 4ас найдем для действительного случая призн = 1, κορί = ρ + q и ио/?2 = ρ — #, а для комплекс- q ного — призн = —1, κορί = ]/р2 + д2 и кор2 =arcsiny g _^_ a . В результате введя для экономии вычислений еще несколько промежуточных величин, но в то же время не стремясь расписать все формулы до последней операции, получим программу: начало вещ а, Ъ, с, ti, Й, дискр, р, q, κορί, κορ2: цел призн; ввод (а, 6, с); ί1:= 2χα; *2:= 2хс; дискр:= b\2 — tlxt2; р:= —b/ti; q:= sqrt(abs(ducKp))/tl; если диск/? < 0 то начало il:=pf2 + ?t2; κορί: = sqrt(ti); кор2: = arcsin (q/κορί) конец иначе начало κορί:= ρ + q; κορ2:= ρ — q; конец; призн:= sign (дискр); вывод (призн, κορί, κορ2) конец Маршрут. Построим теперь йля этой программы ее операторную схему. Она уже не будет линейной, потому что в ней содержатся взаимноисключающие участки вычислений (случай отрицательного и неотрицательного дискриминанта). Для удобства
so ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ ,_ri? ал£ ι _ I г* τ1 \ I ! i 1 ' ЧГ ■-I-I—-δ" ι ι Зис г"} Ι ^ I »gjf -1 -raL ί/' --ό -2- /Ш/ ~-0 LL l·^- ^Λ Π -=δ" Lc; Й Τ Г? Л— ι ι ι ι I I -М- I! ι ι ι ι Ι μ^ I · /W/ rf ( J_ ι ι ■?H Рис. 1.4. Операторная схема, содержащая условие.
' § 1.3. НАКОПЛЕНИЕ ΦΛΚΤΟΕ. ПРОГРАММЫ ОБЩЕГО ВИДА 31 дальнейшего анализа обозначим каждый из операторов именэм. величины, сопоставленной его результату, сделав очевидные исключения для операторов условия и вывода. На схеме (рис. 1.4) проложим информационные связи, используя то же правило: связь прокладывается от результата оператора S к аргументу оператора Ту если им сопоставлена одна и та же величина χ и существует хотя бы один путь по схеме от S к Г, вдоль которого ни один из. операторов, кроме S, не вырабатывает величину х. У нас уже промелькнуло образное сравнение этого пути с маршрутом доставки значения величины χ от оператора S к оператору Г. Сейчас нам, пожалуй, будет самое подходящее время закрепить этот образ в виде термина. Одно из новых явлений, которые мы обнаружили на этой схеме, это то, что доставка значения от результата к аргументу, т. е. реализация проложенной информационной связи, может происходить более чем по одпому маршруту: значение· дис доставляется к оператору призн либо по маршруту (due, p, qy <C,2l', κορί,κορ2, призн),либо(дис,р,д,<С, κορϊ',κορ2!, призн). Второе наблюдение касается связок информационных связей: до сих пор каждая связка была как бы пучком стрелок, идущих от одного результата к нескольким использующим его аргументам. Сейчас же (рис. 1.5) их конфигурация усложнилась: в случае γ I \ I \ ι \ г1 1 / Υ γ / / / ' \ / • , , γ *)юр1 δ)κορΖ Рис. 1.5. Новые виды связок для κορί и кор2. связки кор2 информационные связи группируются у аргумента„ а в связке κορί группировка произошла и у аргумента, и у результата. Это заставляет нас сделать заметку на будущее (правда „ очень скорое): при выборе имени величины для обозначения результата это имя нужно расставить не только на аргумент (или аргументах), двигаясь по стрелкам, но и потом перенести имл « этого аргумента на другой результат, навстречу стрелке соответствующей информационной связи.
32 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ Следующее, что мы хотим сделать,— это провести сечения последовательности выполненных операторов, чтобы определить конкурирующие информационные связи и число величин в экономном распределении памяти. При проведении сечений мы опять- таки сталкиваемся с новыми фактами. У нас по-прежнему есть, как бы сказать, доминирующее направление вычислений, задаваемое стрелками между операторами, при этом распадающееся на некотором участке на две ветви, которые потом снова сходятся. Мы уже понимаем, что на нашем примере изображен простейший случай и что, желая выжать из этого конкретного примера все лолезное, мы должны стараться сформулировать наши возможные новые правила в наиболее общей форме. Само понятие сечения не зависит от сложности схемы. Мы всегда рассекаем только одну стрелку перехода от одного оператора к другому. Вопрос в том, какие информационные связи мы рассекаем этим сечением. Раньше ответ был прост: все те, которые начинаются выше и кончаются ниже данного сечения. Простота его для линейной программы была в том, что каждый оператор программы оказывался либо ниже, либо выше сечения. Здесь это уже не так: выше или ниже оператор κορί по отношению к оператору кор2 — этот вопрос не имеет ни смысла, ни ответа. Вспомним, однако, как мы использовали сечение: мы каждой пересекаемой информационной связке сопоставляли величину, хранившую выработанное значение и говорили себе: вот эти величины заняты в момент выполнения рассекаемого оператора *), поэтому его результат нельзя присвоить ни одной из этих занятых величин, и информационная связь, начинаемая этим результатом, является конкурентной со всеми другими рассекаемыми информационными связями. Тогда мы можем сказать так: сечение некоторого оператора S рассекает по определению те и только те информационные связи, маршруты которых содержат 5, или: информационная связь, начинаемая результатом некоторого оператора 5, конкурентна с теми и только с теми информационными связями, маршруты которых содержат S· Эта формулировка, хотя и выглядит более сложной, зато более непосредственно выражает суть дела (принцип сохранения информационных связей), а главное,— уже не зависит от конкретной сложности схемы: если мы знаем информационные связи и реализующие их маршруты, мы можем построить все сечения, ибо вопрос о принадлежности того или иного оператора тому или иному маршруту решается однозначно. Подробная процедура экономии. На рис. 1.6 изображены все 14 сечений схемы примера 9. Нам с ними еще придется поработать, *) Мы для краткости употребляем вольное выражение, так как рассекаем фактически не оператор, а выходящую из него стрелку перехода.
§1.3. НАКОПЛЕНИЕ ФАКТОВ. ПРОГРАММЫ ОБЩЕГО ВИДА ©- ©- ®- ©- ®- & <2> ®- 0- ОУ-F I гг- ^4— ^ if -зл L^J кор1 L-t— 7& I jz±z кор2 н5ПГ -rr-i J 44- -^ I I tz Ί ' _ ^ffi due ν— ·** !* ■—гз£ —" ;i« en: LJl k- /?Ш/У игзг г-ι Sr j a wpf I-37 ® r-4 xopf I -& -@4 -®3 Рис. 1.6. Распределение памяти для примера 9.
34 ГЛ.*1 СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ поэтому они занумерованы. Справа указана ширина каждого сечения, т. е. количество взаимно конкурирующих информационных связей. Максимальная ширина равна четырем. Приступим к распределению памяти согласно процедуре, отработанной нами'для линейных программ. Нам имеет смысл одивг раз выполнить ее-во всех деталях. Читателю рекомендуется перерисовать рис. 1.6 без имен величин и проставлять их на рисунке* по мере продвижения по схеме. Сечение 1. Три результата. Обозначаем их а, & и с и переносим имена на' аргументы по направлению информационных, связей. Сечение 2. Новый результат, Ъ и с заняты, а свободно- Обозначаем им результат и соответствующие аргументы. Сечение 3. Новый результат, а и Ъ заняты, с свободно·. Обозначаем им результат и (соответствующие) аргументы. Сечение 4. Новый результат, а и Ъ заняты, с свободно- Обозначаем им результат и аргументы. Сечение 5. Новый результат, α и с заняты, Ъ свободно- Занимаем его. Сечение 6. Новый результат, Ъ и с заняты, а свободно- Занимаем его. Сечение 7. Результатов нет. Сечение 8. Новый результат, а и с заняты, Ъ свободно- Занимаем его. Сечение 9. Новый результат, а к с заняты, Ъ свободно- Занимаем его. Однако, когда мы перенесем Ъ на аргументы операторов кор2 и выв, мы увидим, что эта же величина должна быть соотнесена результату оператора κορί'. Однако этого делать нельзя, так как в сечении 12 этот результат конкурирует, в частности, с информационной связью от ρ к кор2\ которой в свое время уже- была сопоставлена величина Ъ. Нам не остается ничего другого, как взять для рассматриваемой связки κορί новую величину d- Сечение 10. Новый результат, с и d заняты, а и Ъ свободны. Берем а в качестве величины для результата и опять обнаруживаем, что его надо перенести и на результат кор2'. Анализ 13-п> сечения, однако, позволяет это сделать. Сечение 11. Результатов нет. Сечения 12и13. Величины результатам уже сопоставлены- Сечение 14. Новый результат, а и d заняты, Ъ и с свободны- Занимаем Ъ. Проанализируем итог работы. В первом приближении процедура экономии памяти сработала как нужно: максимальная ширина схемы (12-е сечение) равна четырем, именно столько величин мы использовали. Анализ сечений по-прежнему давал нам сведения: о занятых величинах в момент выполнения рассматриваемого оператора. Однако ситуация, с которой мы столкнулись в 9-м сечении,.
• § 1.3. НАКОПЛЕНИЕ ФАКТОВ. ПРОГРАММЫ ОБЩЕГО ВИДА £5 нам показала, что для того, чтобы принять здесь правильное решение о конкурирующих связках, нам оказалось необходимым, двигаясь вдоль (и навстречу) стрелок информационных связей, образующих связку, просмотреть обстановку в 12-м сечении.. То, что мы сделали это без труда, не делает положение менее серьезным: мы хорошо понимаем, что имеем дело с простейшим примером, лишь намекающим на реальные сложности. Важен один вывод: хотя по-прежнему единственной предпосылкой к определению конкурентности для нас является информация о том, принадлежит ли оператор, начинающий информационную связь, маршруту другой связи, итоговый, так сказать, вывод о том, ■с какими связками конкурирует данная, делается более сложным образом. Нам нужно теперь делать вышеупомянутую «проверку на принадлежность» для всех результатов, входящих в данную связку. Именно так мы поступали в 9-м и 10-м сечениях. Углубленное представление. Поразмышляв над сделанным выводом, а также над примером в целом, мы можем заключить, что наши представления о проблеме экономии памяти существенно расширились. Организуем по этому поводу нечто вроде промежуточного финиша. Для каждой информационной связи существуют реализующие эту связь маршруты — цепочки операторов, начальный из которых вырабатывает некоторую величину в качестве результата, последний воспринимает эту величину и ни один из-внутренних (т.е. между начальным и конечным) не вырабатывает эту величину. Одна связь может реализоваться по нескольким маршрутам. Информационные связи образуют связки, т. е. такие группы «связей, которые смыкаются друг с другом своими концами,— аргументами или результатами операторов. BcfeM аргументам и результатам операторов, попадающим в одну связку, при любом распределении памяти должна сопоставляться одна и та же величина. (Прочитав этот абзац еще раз, мы поймем, что понятие связки у нас пока что какое-то приблизительное. В случае линейных программ оно было точным: это — все связи, начинаемые одним результатом. В общем случае оно еще подлежит точной формулировке.) На первый взгляд, можно было бы сказать, что к связке относятся все информационные связи, «концам» которых в исходной схеме была сопоставлена одна и та же величина. Однако, уже в только что рассмотренном примере мы, между прочим, столкнулись с тем, что информационные связи, осуществленные в исходной схеме через величину £1, распались совершенно четко на две связки: одна с маршрутами (£1, £2, дис) и (£1, £2, due, p, q) и другая с одним маршрутом (£1, кор\). Это само по себе не ново. Например, каждый из маршрутов (G, Я), (Я, /), (/, /) и (/, К) на рис. 1.3, а) реализует информационные связи, попадающие в разные связки,
36 ГЛ. i. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ хотя и имеющие общие операторы. Новым же оказалось то, что стремление к наиболее экономному распределению памяти в соответствии с принятой нами процедурой привело к тому, что этим двум связкам (ti иН') были сопоставлены разные величины а и Ь* Мы видим тем самым, что задача экономного распределения памяти не может быть поставлена в такой, можно сказать, наивной формулировке: «натолкать» как можно больше исходных величин программы в одну ячейку. Пример 9 подсказывает, что «единицей» распределения памяти является не вся «область действия» исходной величины, а отдельные связки информационных связей, осуществляемых через нее. Возвращаясь к использованной процедуре экономного распределения памяти, мы видим, что она, прежде всего, усложнилась. Ьо-первых, более сложно строятся сечения. Смысл сечения теперь выглядит следующим образом: мы рассекаем в месте оператора S те и только те информационные связи, для которых реализующие их маршруты содержат в себе S в качестве начального или внутреннего операторов. Во-вторых, анализ одного сечения недостаточен для правильного определения, с какими информационными связями может конкурировать связь, начинаемая результатом г оператора Sz нужно проверить сечения, проведенные для всех операторов, вырабатывающих результаты, входящих в ту же связку, что и результат г. Сечение, по-прежнему, нам показывает, какие величины за-г няты в момент выполнения данного оператора, но уже не дает возможности заключить, что все остальные величины в этот момент свободны в том смысле, что их можно занимать новым результатом. В-третьих, сама процедура утратила свою однозначную направленность. Имея в программе разветвления, мы можем по- разному обходить цепочки операторов. В примере 9, например, мы могли бы сначала обходить правую цепочку (сечения 11—13), а лишь потом левую (сечения 7—10). И хотя в данном случае мы получим те же четыре величины (читатель может в этом поупражняться), подсказанные нам сечением 12, тем не менее доказательством того, что процедура дает всегда минимальное число величин, мы в общем случае, включающем разветвления, уже не располагаем. Программа с циклами. Следующим шагом в нашем содержательном анализе задачи будет исследование программ, содержащих циклы. Π ρ и м е ρ 10. Вычислить величину а по рекуррентному соотношению ·, TCefen=ln(|tg(an_i)|).
§ 1.3. НАКОПЛЕНИЕ ФАКТОВ. ПРОГРАММЫ ОБЩЕГО ВИДА 37 Даны а0 и Ь0, а также условие на окончание: |&п| < 0.1. Программа получается буквально по исходным формулам. начало вещ а, Ь, с, dt e; ввод (а, Ь); повторение: с:== tg (a); d: = Ъ + с; е:= abs (с); а:= d/e; Ъ:— In (e); если abs (b) ^0.1 то на повторение; вывод (а) конец Построим операторную схему и проведем информационные связи. Сечений и величин здесь не много, поэтому мы для экономии места нанесем их на один и тот же чертеж (рис. 1.7). Читателю Рис. 1.7. Операторная схема, содержащая цикл. же мы советуем, как и раньше, перерисовать схему и информационные связи для того, чтобы самому воспроизвести работу процедуры экономии памяти. Обращаем внимание, что ширина каждого сечения в схеме не превышает двух. Еще раз проследим работу
83 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ процедуры во всех деталях (в качестве новых величин будем брать а, Ь и т. д.). Сечение 1. Два новых результата а и Ъ. Разносим эти имена но всем аргументам и результатам соответствующих связок: а на аргумент тангенса (tg), от него на результат деления (/), а от последнего «а аргумент выв; Ъ на аргумент сложения (+)> от него на результат логарифма (In), а от последнего на аргумент сравнения (<). Сечение 2. Новый результат. Конкурирует с Ъ. Берем а, сопоставляем результату и разносим на аргумент сложения и вычисления abs. Сечение 3. Новый результат. Конкурирует с а. Берем Ь, сопоставляем результату и разносим на аргумент деления. Сечение 4. Новый результат. Его связка конкурирует как с а, так и с Ь. Берем с, сопоставляем результату и разносим на аргумент деления и вычисления In. После этого все позиции аргументов и результатов заняты величинами, так что остальные сечения просматривать незачем. Трудности с сечением. На первый взгляд в четвертом сечении мы имеем ту же ситуацию, что и в девятом сечении примера 9. Там у нас связка κορί оказалась конкурирующей со связкой q (новое имя а), связкой дис (новое имя с) и связкой ρ (новое имя Ь), и мы взяли еще одну величину d. Разница, однако, в следующем. В примере 7 все эти связки оказываются конкурирующими также и друг с другом, так что какие бы имена величин мы ни выбрали, нам обязательно потребуются 4 величины. В рассматриваемом же примере мы обнаруживаем, что связка результата оператора aba конкурирует со связками результатов операторов сложения (величина Ъ) и деления (величина а), хотя последние две связки друг с другом не конкурируют. Таким образом, необходимость введения третьей величины выглядит какой-то недостоверной. Может быть, при другом порядке распределения памяти мы могли бы этим связкам сопоставить одинаковые величины и тогда все-таки обойтись двумя величинами, на что нас, казалось бы, наталкивает ширина сечений, как мы уже заметили, нигде не превышающая двух. С другой стороны, нам с определенностью кажется, что при распределении памяти мы в любой момент поступали единственно возможным образом, и читатель вправе предположить, что здесь никак не обойтись только двумя величинами. Не исключено, что он даже найдет индивидуальное доказательство этому примеру, но нам сейчас важно сделать другой, более общий вывод: ширина сечения уже не может быть для нас ориентиром в определении числа величин, требуемых для экономного распределения памяти. Все это, вместе взятое, окончательно хоронит попытку спасти нашу процедуру как способ наилучшего распределения памяти*
§ 1.3. НАКОПЛЕНИЕ ФАКТОВ. ПРОГРАММЫ ОБЩЕГО ВИДА 39 мы получаем с ее помощью некоторое распределение памяти, но уже не можем утверждать, что оно наилучшее. Несовместимость. Однако суждение в такой негативной форме нас не устраивает. Прежде чём расстаться с найденной для линейных программ и подправленной для общего случая процедурой экономии памяти, нам нужно более внимательно рассмотреть, что в ней достоверно, а что нет. Давайте еще раз посмотрим,что мы в ней делаем: двигаясь по операторной схеме с построенными информационными связями, мы: а) определяем, какие связки друг с другом конкурентны, а какие нет, и б) назначаем связкам те или иные имена величин, стараясь обойтись их наименьшим количеством. Мы уже увидели, что для определения взаимной конкурентности связок (нам уже пора заменить это случайно появившееся образное название на специальный термин — давайте называть это несовместимостью связок) нам не нужны имена величин: две связки несовместимы, если начальный оператор какого-нибудь маршрута, реализующего какую-нибудь информационную связь одной связки, является начальным или внутренним оператором какого-нибудь маршрута, реализующего какую-нибудь информационную связь другой связки (извините за длинную фразу — зато совершенно точно!). Таким образом, информация о несовместимости по операторной схеме обнаруживается однозначно, а свобода выбора и неоднозначность результатов у нас получается при назначении величин на связки. Сама по себе неоднозначность не страшна: она дает возможность строить разные варианты распределения памяти. Для линейных программ она также не мешала нам найти наилучший результат: там мы знали заранее наименьшее число величин и как его достичь. При попытке сохранить алгоритм в общем случае мы себя привязывали к выбранному направлению движения по схеме и старались назначить величину новому результату немедленно по его обнаружении. Из-за сложной структуры связок, мы, так сказать, опережая события, «забрасывали» имена величин на еще не пройденные участки схемы и тем самым, когда впоследствии попадали туда, оказывались в тесных рамках ранее сделанных выборов. Действуя «в малом», в окрестности одного сечения, мы пользовались частичной информацией о несовместимости только данного нового результата с его конкурентами, не имея общей картины о несовместимости связок для программы в целом. Так у нас появляется мысль о разбиении процедуры распределения памяти на две части: а) получение общей информации о несовместимости и б) на основе анализа общей информации о несовместимости выбор того или иного распределения памяти, желательно наилучшего. Попробуем немедленно проверить эту идею на нашем примере 10. Нам надо в каком-то наглядном виде представить информацию о
40 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ несовместимости связок. Соберем ее сначала, так сказать, в буквальном виде. Сначала связки надо обозначить. Обозначим их символами операторов, чьи результаты начинают эти связки. Это будут: (eel,/), (eel, In), tg, +, abs. Мы имеем (eel,/) несовместим с (вв2, In) и abs (eel, In) несовместим с (eel,/) и tg tg несовместим с (eel, In) и + + несовместим с tg и abs abs несовместим с + и (ββί,/) Эта таблица не очень наглядна, но мы улавливаем какую-то цикличность в ее строении, которую хотелось бы представить в более доступном обозрению виде. Цикл — это окружность — или замкнутая ломаная. Замкнутая ломаная в свою очередь — это вершины и стороны. Что у нас вершины и что стороны? Сторона соединяет две вершины, понятие несовместимости относится к двум связкам. Хорошо! Мы обозначаем связки большими точками — вершинами ломаной, а вершины несовместимых связок соединяем линией. Получаем рис. 1.8. Граф несовместимости. Автор вправе рассчитывать, что большинство читателей знакомо с математическим понятием графа. Мы его формально введем в следующей главе, Рис. 1.8. Наглядное представление ий- а для новичков скажем, формации о несовместимости связок. что (неориентированный) граф состоит из вершин и ребер, их соединяющих. На чертеже вершины изображаются точками (или кружками), а ребра —соединительными линиями. Вершины, соединенные ребрами, называются смежными. Вернемся к нашей задаче. Граф на рис. 1.8 изображает сводные данные о совместимости и несовместимости связок информационных связей. Сам граф можно в связи с этим назвать графом несовместимости. Вершинами графа являются связки. Смежными вершинами в графе являются несовместимые связки, и наоборот, любые две несмежные связки являются совместимыми. Распределение памяти на графе несовместимости выглядит так, что надо
§ 1.3. НАКОПЛЕНИЕ ФАКТОВ. ПРОГРАММЫ ОБЩЕГО ВИДА 41 каждой вершине сопоставить величину, но так, чтобы никакой паре смежных вершин не сопоставлялась бы одна величина. Экономия будет достигаться тем, что разным несмежным вершинам будет сопоставляться одна и та же величина. Опять-таки автор может рассчитывать, что часть читателей, прочитав условие задачи экономии памяти в этой формулировке, усмотрит в ней прямую связь со знаменитой задачей теории графов — задачей о раскраске вершин графа: надо раскрасить вершины графа в наименьшее число красок так, чтобы никакая пара смежных вершин не оказалась раскрашенной одной краской. Этот факт сам по себе очень интересен, но сейчас мы не будем отвлекаться, а опять вернемся к нашему примеру. Распределим память для наших связок. Так как они в графе несовместимости образуют цикл, то все равно, с какой вершины начинать. Сопоставив вершине {eelj) величину а, мы неизбежно сопоставим смежной вершине (ев2, In) величину 6, но следующей связке tg можем опять сопоставить а. Величины а и Ь при движении, по часовой стрелке будут чередоваться. Так будет, пока мы не подойдем к вершине abs, замыкающей цикл. Мы не только видим, что ей неизбежно придется сопоставить третью величину, но и понимаем, когда бы мы могли обойтись только двумя: если последняя вершина Ζ будет смыкать цепочку четного числа вершин, то ее концам будут сопоставлены разные величины, и вершине Ζ понадобится третья величина; если цепочка содержит нечетное число вершин, то ее концам сопоставлена одна величина, тогда вершине Ζ можно сопоставить вторую величину. Как видно, у нас благодаря введению такой новой конструкции, как граф несовместимости, появляется источник доказательства минимального расходования памяти совершенно другой природы, уже очень косвенно связанный со структурой программы, но зато выдающий исходную· информацию для распределения памяти в «чистой» форме, не обремененной никакими деталями. Получив эту новую форму нам, естественно, будет интересно перепроверить, как она работает дли разобранных щрщ ранее примеров экономии памяти. Автор рекомендует читат$Д*ш Самостоятельно построить графы несовместимости для прищуров 1—9, честно предупредив, что им придется немного повозиться, чтобы изобразить их на рисунке достаточно красиво и наглядно. Для контроля и небольшого последующего обсуждения все графы изображены на рис. 1.9. Связки в примерах i, 2 и 9 обозначены именами величин, использованных в начальном варианте программы. Величины, выбранные при экономном распределении, помещаются рядом с соответствующими вершинами графа. Примеры 3 и 4 пропущены, так как нам еще не ясно, как строить операторную схему для про- грамм1 содержащих операторы цикла. В примерах 5 и 6г 7 и &
42 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ связки обозначаются именами операторов, вырабатывающих относящиеся к этим связкам результаты. Во всех случаях минимальность числа величин, использованных для «раскраски» вершин графа несовместимости, очевидна. Обращает на себя внимание наличие в примерах 5, 6 и 9 своего рода ядер в графах — групп вершин, попарно смежных друг другу и поэтому требующих заведомо разных величин. Все остальные вершины существенно Рис. 1.9. Графы несовместимости, а) Примеры 1, 2. б) Примеры 5, 6. в) Примеры 7,8. г) Пример 9. д) Пример 10. «более.слабо» соединены друг с другом ребрами и поэтому на их долю хватает того максимума величин, которые потребовались для ядра. Граф примера 10 таким свойством не обладает: в нем нет трех попарно смежных вершин, однако он требует трех «красок». Мы уже, пожалуй, привыкли к тому, что мелкие отличия оказываются источником серьезных проблем. Так и сейчас: мы обязаны сказать себе,, что раскраской вершин графа несовместимости как самостоятельной задачей нам нддо будет в свое время серьезно заняться.
§ 1.4. НАКОПЛЕНИЕ ФАКТОВ. ПОДВЕДЕНИЕ ИТОГОВ 43 § 1.4. Накопление фактов. Подведение итогов Программа с процедурами. Обогатившись такой важной Конструкцией, как граф несовместимости, мы спешим замкнуть наш содержательный анализ исследованием программ, содержащих функциональные обозначения, раскрываемых (для алгола) с помощью описаний процедур. Пример 11. Вычислить ■ргщ-, если х<1) {х — b)F(x), если #^1, тде F(r) = г2 + 1. Вычисление F(x) оформим в соответствии с правилами алгола в качестве описания процедуры. Получаем исходную программу начало вещ Ь, ν, χ, у, ζ; вещ проц F(r)\ вещ г; начало вещ /; /:= rf2; F:= f + 1 конец; ввод (Ь, х)\ если (χ <Ζ 1), то начало ζ:= χ + b; у: = zlF(x) конец иначе начало ν:= χ — b; y:= vxF(x) конец вывод (χ) конец При построении операторной схемы нам нужно решить, как изображать связь тела процедуры с местами указания ее выполнения, а также фактических параметров с формальными. Не занимаясь этим вопросом в его полном объеме, мы заметим, что фактический параметр в указателях функции один и тот же и сам вызывается именем. Тайим образом, тело процедуры выполняется с именем величины χ вместо г. В местах указателей функции будут выполняться передачи управления на тело процедуры, а в конце тела процедуры подразумевается наличие «оператора возврата», который обеспечивает продолжение вычислений с того места, откуда было вызвано выполнение процедуры. В результате получаем схему, изображенную на рис. 1.10, а). Структура схемы достаточно проста и мы, уже. не связываясь с изжившими себя сечениями, определяем взаимную совместимость и несовместимость связок информационных связей. Анализируя операторы схемы и маршруты информационных связей, обнаруживаем, для каких маршрутов данный оператор является начальным, и для каких — внутренним. Проделав это систематически, получаем показанную на рис. 1.11 таблицу. В позиции таблицы {i-я строка, /-и столбец) мы ставим Η (начальный оператор), если в /-й связке есть маршрут, который начинается i-м оператором, и В У =
44 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ (внутренний оператор), если в ;-й связке есть маршрут, который MHFtyeT i-й оператор. Построение такой таблицы позволяет более однотипно проверять попарную несовместимость связок. Берем колонки ]\ и /2 и-их содержимое объединяем. Если у нас в результате хоть в какой-то позиции окажется вместе Η и Η или Η и В, то связки jL 66 & 4-, ι \ / I I I / хЩбд х\ J" 4 1 / I I * I ШГ ю a I I И ί \ 1 Ή 55Ξτ - * Ряс. 1.10. Операторная схема с процедурой, а) Начальный вид. б) Схема с новыми информационными связями. и /2 несовместимы, так как это совместное появление Η, Η или И, В означает, что соответствующий оператор имеет обе ©елцчины своими результатами или является для некоторого маршрута одной из связок начальным, а для другой — внутренним, Ч90у Жак мы установили, как раз и является условием существовав конкурирующих информационных связей»
§ 1.4. НАКОПЛЕНИЕ ФАКТОВ. ПОДВЕДЕНИЕ ИТОГОВ 45 Результирующий граф несовместимости также показан рядом € таблицей на рис. 1.11. Его раскраска не составляет никакого труда, и мы видим, что для правильной работы программы достаточно обойтись только двумя величинами. В этом примере, однако, нам будет полезно переписать программу в новых обозначениях величин, и для того чтобы не нарушать формальные правила алгола 60, которые не разрешают изображать_одним именем 1 88' < 1 + 3 t ] +/ / s 1 Х | м b Η в χ Η В В В 7 Η в в υ Η В В f ι Η F Η 9 - Η Η α) *δ) Рис. 1.11. Построение графа несовместимости для примера 11. а) Таблица, б) Граф. функцию и переменную, мы возьмем четыре величины Ь, х, / и F, которыми и «раскрасим» наш граф. В результате экономии памяти получим следующую программу: начало вещ Ъ> х\ вещ проц F{r)\ вещ г; начало вещ /; /:= r|2; F:= / + 1 конец; ввод (Ь, х)\ если (х < 1) то начало Ь: = χ + b; x:=z blF(x) конец иначе начало b:= x — b; x\= bxF(x) конец; вывод (х) конец Расширение информационных связей. А теперь сделаем то, чего, будучи убежденными в правильности наших процедур экономии памяти, мы до сих пор не делали ни разу: построим снова по полученной программе операторную схему (рис. 10, б)), а для нее проложим информационные связи. Мы имеем b в качестве результата операторов + и — и ее же в качестве аргумента операто-
46 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ ров / и X. Вспомнив определение маршрута, мы обнаруживаем,, что цепочки операторов (+, f, +1, χ) и (—, f, +1, /) удовлетворяют этому определению так же, как и те, которые мы прокладывали в операторной схеме рис. 1.10, а); а именно: (+, f, +1, /) и (—, |, +1, X). В итоге оказывается, что совокупность информационных связей в результирующей операторной схеме, благодаря, как нам казалось, вполне законному распределению памяти, расширилась на две связи. Мало того, в исходной схеме мы имели две связки информационных связей (по одной связи в каждой): ζ и v. В результирующей—мы имеем одну связку (с четырьмя связями): Ь* До сих пор все варианты распределения памяти сохраняли как число информационных связей (а также реализующие их маршруты), так и их распределение по связкам. Так что, если бы мы взяли схему рис. 1.10, б) за исходную, мы никогда не могли бы для нее подобрать такое распределение памяти, при котором результат совпал бы со схемой рис. 1.10, а), так как мы всем аргументам и результатам связки Ъ по нашим правилам обязаны сопоставлять одну и ту же величину. Таким образом, принятая нами процедура экономии памяти оказывается необратимым преобразованием исходной схемы. Ситуация слишком серьезна, чтобы не разобраться в ней как следует. Самое главное то, что, как нам казалось, мы на каждом шагу поступали правильно. Давайте еще раз перечислим шаги решения задачи: — построение операторной схемы, — прокладка маршрутов и построение информационных связей,. —. построение графа несовместимости, — «раскраска» графа несовместимости, — распределение памяти согласно «раскраске». Вспомнив правила выполнения каждого из этих шагов, мы понимаем, что секрет кроется в процедуре прокладки маршрутов. Цепочка операторов в исходной схеме (рис. Ι.ΙΘ,α) (+, f, +1, Χ) не может осуществиться и смыслом задачи не предусмотрена. Аргументу ν оператора X предписано использовать только результат ν оператора — . Процедура вычисления F(x) так и работает: оператор возврата передает управления не любому из операторов f или X, а выбирает один из них в строгой зависимости от места вызова процедуры. Попав на | от +, мы уйдем на /, попав на f от —, мы уйдем на X, а перекрестные связи от — к / и от + к χ невозможны. Таким образом, мы видим, что конструкция операторной схемы так, как мы ее ввели, не учитывает, что в реальной программе не все цепочки операторов, которые можно формальна построить по схеме, на самом деле фактически выполняются. Первой реакцией на это открытие была бы попытка так подправить определение схемы, чтобы цепочки, невозможные в каком-та смысле в исходной схеме, обязательно оставались бы невозможными в результирующей. Например, мы видим, что цепочка (+у
§ 1.4. НАКОПЛЕНИЕ ФАКТОВ. ПОДВЕДЕНИЕ ИТОГОВ , 47 t» +1» X) невозможна хотя бы потому, что на таком пути для оператора X не оказывается питающего его результата. Мы можем потребовать, чтобы эта цепочка оставалась бы невозможной и запретить любому результату вдоль этой цепочки сопоставлять ту же величину величине v. В результате связки ζ и ν окажутся несовместимыми. Однако, еще не думая, насколько это усложнит правила построения графа несовместимости, мы обязаны подумать, что нам это усложнение даст? Ведь на самом-то деле, без всякой теории, величины ζ и υ можно направить в одну ячейку! Эти информационные связи никогда не будут реализоваться одновременно и поэтому они не конкурируют. Реально, нам важно лишь, чтобы ни одна информационная связь, ни один маршрут не нарушились бы. А если в результате интенсивной экономии памяти у нас чисто формально появятся новые маршруты и сольются какие-то связки — так это пусть! Таким образом, у нас появляется новое и принципиальное допущение: мы считаем правильными такие распределения памяти, при которых для любой заданной информационной связи сохраняются все реализующие ее маршруты, но при этом не делаем никаких оговорок в отношении возможности появления новых маршрутов и новых связей. Подведение итога. Итак, мы можем подводить итог содержательному анализу проблемы экономии памяти. Мы рассмотрели способы программирования, которые влияют на объем расходуемой памяти для величин. Мы выяснили, что как выбор алгоритма решения задачи, так и расположение отдельных операторов в программе влияют на количество величин, требуемых для решения задачи. Однако в любом случае имеет смысл более ограниченная постановка проблемы, состоящая в том, чтобы, зафиксировав операторы программы и порядок их выполнения, перейти от исходной программы, в которой имена величин выбирались из соображений удобства обозначений, к другой программе, с минимально возможным числом величин, сохраняющих все возможные информационные связи исходной программы. Мы, далее, нашли, какая информация о программе существенна для систематического решения этой задачи экономии памяти. Для этого нужно знать перечень операторов программы и для каждого оператора знать, какие операторы могут выполняться непосредственно за ним. Для каждого оператора нужно, кроме этого, знать, сколько он имеет аргументов и результатов и какие величины им сопоставлены. Вся эта информация задается в виде операторной схемы, которая наглядно изображается в виде графа (мы уже использовали это слово для графа несовместимости), где вершины — прямоугольники обозначают операторы, а стрелки показывают возможный порядок перехода от одного оператора к другому. Назвав эту конструкцию графом, мы должны дать для
48 ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ него название, в качестве которого выберем самое естественное — граф переходов. Аргументы и результаты и сопоставленные им величины выглядят как дополнительная разметка графа переходов. По операторной схеме строятся информационные связи— стрелки особого рода, идущие от результата а к аргументу Ъу которым сопоставлена одна и та же величина х. Для существования информационной связи необходимо наличие хотя бы одного реализующего ее маршрута, а именно, цепочки операторов, которую можно проложить в графе переходов от оператора с результатом а к оператору с аргументом 6, внутри которой нет ни одного оператора, вырабатывающего х. Информационные связи распадаются на связки, в которых группируются связи, имеющие общие аргументы или результаты. Задача экономии памяти ставится как задача найти среди допустимых распределений памяти для заданной операторной схемы с построенными информационными связями распределение, требующее наименьшее число величин. Допустимым считается такое распределение памяти, при котором для любой информационной связи сохраняются все реализующие ее маршруты. Любое распределение памяти получается «раскраской» графа несовместимости связок информационных связей. В этом графе ребрами соединяются несовместимые связки, т. е. такие, что начальный оператор какого-либо маршрута связи из одной связки является начальным или внутренним оператором некоторого маршрута связи из другой связки. Суть дальнейшей работы. После такого всеобъемлющего резюме уместно задать себе вопрос': а что, собственно, нам осталось делать? Мы рассмотрели достаточно разнообразные примеры, описали все необходимые конструкции, которые помогают экономить память, имеем представление о том, как их надо строить. У нас зреет уверенность, что мы в состоянии справиться с любой программой. Не надо думать, что этот вопрос носит чисто риторический характер. Даже в научных публикациях можно найти немало исследований, завершающихся таким чисто содержательным, неформальным анализом проблемы. На самом же деле мы еще только подступаем к строгому изучению вопроса. Нам, прежде всего, надо дать точные определения всех конструкций во всей их всеобщности; например, такого уточнения требует определение связки. Все утверждения надо подвергнуть логическому анализу: отделить допущения от утверждений, проверив первые на непротиворечивость и доказав вторые. Аналогично, среди конструкций надо выделить исходные и дать точные правила построения вторичных. Этот анализ, и только он, может привести к убеждению в полном решении вопроса, а пока что наши утверждения носят характер правдоподобных рассуждений и определений, базирующихся на частных примерах. Например, мы
§ 1.4. НАКОПЛЕНИЕ ФАКТОВ. ПОДВЕДЕНИЕ ИТОГОВ . 49* могли не наткнуться на пример 11 и действовать в предположении* строгого сохранения информационных связей, не допуская их увеличения. Мы могли слишком долго держаться за понятие сечения, не отделяя процедуры построения графа несовместимости от непосредственного распределения памяти и тем самым незаметно ограничить свободу выбора имен величин. Одним словом,, мы должны дать теперь математическую постановку задачи экономии памяти и на базе этой постановки дать точно описанный метод ее решения, после чего мы сможем вернуться к задаче практического применения этого метода. Этому будут посвящены даль- нейшие главы первой части. Анализ догадок. В данной главе автор попытался приобщить читателя к творческому процессу познания природы задачи и поиска методов ее решения. Естественно, эта демонстрация носила модельный характер, подчиненный интересам изложения и экономии времени читателя. В частности, мы не воспроизводим ошибочные гипотезы, тупики в рассуждениях и неинтересные примеры,, придавая изложению постепенный и поступательный характер. На этом пути можно даже перестараться и создать у читателя обманчивое ощущение легкости и простоты в выполнении каждого шага. Забегая вперед, заметим, что ни в одном из фактических исследований, посвященных экономии памяти, не удалось догадаться сразу до всего, что составляет содержание полной теории, на завершение которой потребовалось около 10 лет. Поэтому мы попробуем дать некоторую оценку степени нетривиальности тех догадок, которые привели нас к достаточно полному представлению о сути дела. Естественно, что эти оценки субъективны и могут иметь для читателя лишь ориентировочный характер. Трактовка экономии памяти как переобозначения аргументов и результатов операторов (команд) програмхмы довольно естественна, но требует хорошего понимания природы программирования и, в частности, функций памяти. Близость понятий переменной величины и ячейки памяти иногда становится»ясной далека не сразу. Дополнительным требованием, скорее психологического, нежели принципиального характера, является способность «узнавать» ту же программу в одежде новых обозначений для используемых величин. Догадка ввести операторную схему как исходную конструкцию требует определенных математических способностей — прежде всего к абстрагированию, к выделению тех свойств программы, которые существенны для экономии памяти,и отвлечению от остальных. В то же время для появления идеи операторной схемы существовало такое важное подспорье как блок-схема программы, которая представляет собой не что иное, как граф переходов, а внутри прямоугольников, соответствующих вершинам-операторам,— начинка, объясняющая их содержание. Для примера на
so ГЛ. 1. СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ ЗАДАЧИ 63od(a,b,c) X t/:-2*a дасир:^ b\Z-t1*tZ I ρι—b/tt q:=zqrt \(abstfwxp))/tf Ϊ да 1 t1>p\l+qW I Kop1l-$qrt(t1) nopZl^ 1 mmfy/Hopf) дискр<0? ^> 1 г призн:~ sign(ducHp) \ db/L - (приз η г нет ι ' Hop1>p+q wp2:-p-f j Ряс. 1.12. Стандартная блок-схема примера 9.
§ 1.4. НАКОПЛЕНИЕ ФАКТОВ. ПОДВЕДЕНИЕ ИТОГОВ 51 рис. 1.12 изображена в принятом стандарте блок-схема программы решения квадратного уравнения (см. пример 9). Отделение аргументов и результатов операторов от обозначающих их величин, введение понятия информационной связи и ее наглядного изображения в виде стрелки от результата к аргументу является наиболее нетривиальной и, вообще, ключевой находкой на нашем пути рещения задачи. Через естественно возникающее понятие сечения для линейных программ и через понятие связки как «единицы» распределения памяти в общем случае мы довольно быстро приходим к полному охвату задачи. Совокупность информационных связей становится важным инвариантом программы, независимым от способов распределения памяти. Так же весьма существенным логическим шагом было «отщепление» сбора полной информации о несовместимости связок в виде графа несовместимости от непосредственного поиска наилучшего распределения памяти как «раскраски» вершин этого графа. Это очень важно с точки зрения конкретной реализации процедуры, экономии памяти: направленный процесс получения однозначно^ информации о попарной несовместимости, связок отделяется от* сугубо неоднозначного, комбинаторного поиска наилучшей рас-_ краски, которая к тому же сама по себе является известной математической задачей. По своему, характеру эта находка — чисто, математической природы. Заметим, что к идее раскраски вершин графа как средства экономии памяти можно прийти, как говорится, с налета, без понятия информационных связей. Рассмотрим задачу экономии памяти как желание поместить в одну ячейку- памяти побольше величин так, чтобы суммарный расход памяти оказался бы наименьшим. Две величины несовместимы, если их; нельзя поместить в одну ячейку памяти, и совместимы в противном случае. Это отношение несовместимости можно представить.. в виде графа, вершинами которого являются величины, а ребра соединяют несовместимые величины. Его наилучшая раскраска даст экономное распределение памяти. Как видно, это «почти», граф несовместимости с двумя существенными, однако, отличиями: во-первых, мы не подозреваем, что аргументы и результаты, обозначенные одной величиной, могут принадлежать разным связкам, и быть поэтому соотнесенными разным ячейкам памяти и, во- вторых, у нас на этом уровне нет никакого подхода к фактическому определению несовместимости. Наконец, обнаружение необходимости расширить множество., информационных связей в определенной степени является делом случая. Догадаться об этом сначала очень трудно, однако, также*, справедливо и то, что анализ математической постановки задачи- дочти неизбежно привел бы к необходимости такого допущения просто для того, чтобы свести в теории «концы с концами», сохраняя ее общность.
ГЛАВА 2 ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ § 2.1. Краткое повторение математических основ Абстрактный объект. Аккуратно написанные математические работы всегда четко разделяют: что определяется или описывается в работе, а что считается известным заранее. В некоторых случаях в отношении этой дилеммы действует ^правило умолчания: все, что не определено или не объяснено явно, предполагается известным. В таком правиле умолчания есть доля риска: читатель должен быть уверен, что понимает необъясненные понятия так же, как они использованы автором. Учитывая дидактическую сторону нашего изложения, мы предложим некоторую помощь читателю и кратко охарактеризуем те математические понятия, с которыми будем работать в этой книге. Хотя все они, без исключения, относятся к азбуке математики, мы тем не менее дадим их сводку, хотя бы для того, чтобы подчеркнуть минимальность того круга понятий, который будет достаточен для развития теории нашего вопроса. Одним из наиболее первичных понятий, владение которым дает в руки ключ к пониманию всеобщности математического метода исследования, является понятие абстрактного объекта. Абстрактный объект — это то, что является предметом математического рассуждения, состоящего из определений, допущений, или постулатов, и утверждений, выводимых из определений и допущений по общепонятным, т. е. опять-таки постулированным правилам логического вывода. Высшую степень абстракции составляют исходные, или первичные, абстрактные объекты,— это те объекты, природой которых мы можем себе позволить не интересоваться вовсе. В математическом рассуждении первичный или, как говорят, произвольный абстрактный объект подчиняется лишь таким допущениям, что его можно «взять» и «рассматривать» под приданным ему обозначением и «отличать» от других объектов. Все остальные свойства или манипуляции с таким объектом находятся за рамками данного рассуждения. Мы не случайно подчеркнули слово «данного», так как в другом рассуждении «тот же» первичный объект может после определенной конкретиза-
§ 2.1. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКИХ ОСНОВ 53 ции выглядеть совсем по-другому, обладая дополнительными -свойствами или внутренним строением. Например, ниже мы определим граф как конструкцию, вершинами в которой могут быть произвольные абстрактные объекты. Позднее же, когда мы станем говорить о графе несовместимости, его вершинами будут связки — объекты весьма сложного строения, в отношении которых читателю придется сделать даже некоторое мысленное усилие, чтобы представление о них ассоциировалось бы с видом точки на плоскости — наглядным изображением вершины графа. Эта свобода и легкость, с которой математик, подобно опытному кинооператору, переключающему объективы кинокамеры, мгновенно переходя от панорамы к крупному плану, меняет уровни абстракции в рассмотрении объектов, выбирая для каждого уровня наиболее подходящую форму наглядного представления об объекте, являются залогом,успеха в эффективном решении математической задачи. При рассмотрении абстрактных объектов следует различать их обозначения и их изображения. Обозначение вводится в рассуждение задающей фразой типа: «Пусть S— оператор рассматриваемой программы». Другие фразы упоминают объект, введенный задающей фразой. Обозначение служит как бы мостиком, связывающим задание и использование рассматриваемого объекта. Строгое изложение четко выделяет задающие фразы, не заставляя читателя догадываться из контекста, о каком объекте идет речь. В некоторых языках различение задания и рассмотрения ранее заданного объекта является частью грамматики языка, как, например, неопределенный и определенный артикли в английском языке, В алголе и некоторых других алгоритмических языках роль задающих фраз играют описания, как, например, цел^г, проц F и т. п. Изображение объекта — это наглядное представление некоторого конкретного объекта. Оно говорит само по себе, какой объект рассматривается, и, вообще говоря, не требует специальной задающей фразы. Кроме исходных абстрактных объектов в математическом рассуждении имеют дело с производными объектами, т. е. получаемыми каким-то образом из исходных. Один из способов состоит в построении, или вычислении, производного объекта из исходного. Этот способ получения подразумевает существование алгоритма,— правила, или предписания, убедительно описывающего отдельные шаги вычислительного процесса, приводящего к построению или нахождению производного объекта. Убедительность означает, что при выполнении алгоритма мы всегда можем выполнить любой очередной шаг, всегда точно знаем, какой шаг надо выполнить, всегда знаем, что наш процесс окончится. В математике есть несколько точных опре-
54 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ делений того, какие вычислительные правила надо считать алгоритмами. Все они опиеыМют один и тот же круг вычислительных процессов, а способ записи алгоритмов очень похож на программирование для ЭВМ. Другой способ получения производных объектов из исходных — это группировка, объединение исходных объектов в составные: наборы и множества. Набор — это абстрактный объект, о котором известно, что он: состоит из определенного конечного числа других объектов — его* компонент. Если дан набор, то даны его компоненты, и, наоборот,, задание компонент полностью определяет набор. Рациональная: дробь — это набор из двух целых чисел — числителя и знаменателя, комплексное число — это набор из двух вещественных чисел — его действительной и мнимой частей, вектор — это набор его координат, многочлен — набор его коэффициентов. Компоненты набора всегда отличимы друг от друга; когда вводится название для набора, вводятся также (при этом различные) названия для его компонент. Два одинаково устроенных набора равны, если; одинаковы (равны) их соответствующие компоненты. Мы не случайно говорим «одинаково устроенных»: комплексное число» 2 + Ы и рациональная дробь 2/6 не равны, хотя имеют равные компоненты. Наборы имеют два способа их обозначений: один — простое символическое обозначение для набора в целом, вводимое обычным? образом, другой — вводит одновременно как обозначения для компонент набора, так и указание на то, как они объединяются в: набор (правила композиции). Ниже следует ряд общеизвестных примеров: дробь г =-£-, комплексное число ζ = а + ib, вектор а = (аь а2, ..., ап), многочлен Р4 = а0 + &\χ + α%χ2 + азх* + а4^4» матрица В = ||bfj|| (i = 1,..., я, j = 1,..., m), треугольник Δ = (α, b, с). Если дано обозначение набора, то иногда его компоненты обозначаются с помощью функций выборки, имеющих вид Я(Г). где Τ — обозначение набора, а К — название соответствующей компоненты, например, Re (ζ), lm (ζ), числитель (г), знаменатель (г).
§ 2.1. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКИХ ОСНОВ 55 Между правилами композиции и функциями выборки имеют место очевидные тождества, как, например, z = (Re(z), Im(z)), ρ = числитель ( —) q = знаменатель (-). Во многих случаях, когда компоненты набора являются как •бы однородными членами, для них не вводят для каждого в отдельности свое название, а, выстраивая их в некотором порядке, пересчитывают. Тогда каждая компонента получает номер, который и является названием компоненты. В этом случае функция выборки указывается по-другому: номер компоненты помещается в качестве нижнего индекса либо у обозначения набора (как в «случае вектора), либо у общего символа компоненты (как в случае матрицы В). Множество и соответствие. Исключительно важным для всех математических построений является объединение объектов во множества. Лучшее пояснение природы множества принадлежит основателю теории множеств Георгу Кантору, который сказал, что «под ,,множеством4' мы понимаем любое объединение в одно целое Μ определенных вполне различаемых объектов т из нашего восприятия или мысли (которые называются ,,элементами4' А/)». Утверждение о принадлежности элемента т множеству Μ обозначается т^М (т принадлежит М). Все разнообразие способов объединения элементов во множества сводится в конце концов либо к заданию способа «получения» элементов множества, либо к заданию характеристического свойства, позволяющего «отличать» элементы множества от других объектов. Поскольку логически допустимо, что процедура получения элементов может, оказаться безрезультатной, а характеристическое свойство никогда не выполняется, мы должны допустить существование пустого множества, не содержащего ни одного элемента. Знак 0- является универсальным обозначением для пустого множества. Разнообразие общих утверждений также сводится в конце концов к утверждениям двух типов: а) утверждению о существовании элемента с некоторым свойством, принадлежащего множеству; б) утверждению о выполнении некоторого свойства для всех элементов данного множества. Доказательство тех или иных общих утверждений об элементах некоторых множеств является, в офщем, конечной целью любого математического рассуждения. Со множествами и их элементами связано еще одно фундаментальное понятие — соответствия. Соответствие устанавливает
56 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ связь между элементами двух множеств Μ и N такого тина, что если нам дан некоторый элемент множества М, то нам также дан некоторый вполне определенный этим соответствием элемент множества N. Простейшим видом соответствия является тождественное, т. е. когда для элемента множества Μ мы «узнаем» во множестве N равный ему элемент. Когда соответствие S определено для любого элемента из Мг то мы говорим об отображении S множества Μ во множество Νι S :M-+N. Соответствующий элемент η из N называется образом своего прообраза т из М. Эта связь изображается равенством η = S(m)+ Множество Му тождественно отображаемое во множество Nr называется подмножеством множества ЩМ cz N). Об N говорят,, что оно включает множество М. Пустое множество по определению полагают подмножеством любого множества. Если в отображении S каждый элемент из N является образом некоторого прообраза из М, то мы говорим об отображении множества Μ на N. Множество N в этом случае также называется образом своего прообраза М. Если каждый элемент из N в отображении S множества Μ на N является образом только одного элемента из М, то тогда можно указать обратное отображение S—1 множества N на М, когда каждому образу S(m)^N ставится в соответствие его прообраз т е Μ. В таком случае мы говорим о взаимно однозначном соответствии элементов множеств Μ и Ν, а сами Μ и N называются эквивалентными множествами. Если между элементами множеств Μ и N имеется тождественное взаимно однозначное соответствие, то эти множества называются равными (М = Лг). Иногда можно прочитать: «множества называются равными, если они состоят из одних и тех же элементов». На самом же деле, это вольная формулировка, хорошо показывающая разницу между живой речью и строгим математическим языком. Выяснение смысла лаконичного выражения «одних и тех же» как раз и приведет к понятию соответствия и тем определениям, которые были только что даны. Сказанное не означает, что математику противопоказана живая речь: педантичное повторение всех определений и выписывание в доказательстве абсолютно всех логических этапов рассуждения сделает изложение громоздким, скучным и неэффективным. Используя, однако, «обычные» слова, сокращения и рассуждения по аналогии, математик должен уметь воссоздать мысленный каркас безупречных построений, придающих точность изложению: в таком умении сочетать логику математического рассуждения со строем человеческого языка общения й заключается то, что мы называем математической культурой.
§ 2.1. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКИХ ОСНОВ 57 Имеет место простое утверждение: если одновременно Μ cz Ν и N Q Μ, το Μ = iV. Действительно, поскольку TV cz Af, то для любого η ^ N есть равный ему элемент из М. Это значит, что в отображении Μ в N каждый элемент из N является образом и при этом только одного (в силу тождественности соответствия) элемента из М. Тем самым, соответствие между Μ и N является тождественным и взаимно однозначным, т. е- Μ = N. В основе практически всех множеств, рассматриваемых в математике, Лежит натуральный ряд и его подмножества, в частности, я-отрезки натурального ряда, т. е. множества всех натуральных чисел к, таких, что 1 ^ к ^ п. Множество М, эквивалентное некоторому тг-отрезку, называется конечным множеством, а число η (равное, естественно, числу элементов в М) — мощностью множества М. Пустое множество также считается конечным с мощностью,-равной нулю. Все остальные множества называются бесконечными. Бесконечное множество, эквивалентное натуральному ряду, называется счетным. Если соответствие между конечным или счетным множеством Μ и тг-отрезком или натуральным рядом задано, то Μ называется занумерованным множеством, соответствие — нумерацией его элементов, а образ элемента из М" — его номером. Занумерованные множества иногда называют упорядоченными, но это не вполне точно. Множество Μ называется упорядоченным, если для любой пары различных элементов этого множества тжт! определено отношение порядка (т < яг'), обладающее свойствами: а) если т < т\ то неверно, что т' < т, б) если т < т! и т! < т", то верно, что т < т". Если Μ — занумерованное множество (М = {mj}), то между его элементами можно всегда ввести отношение порядка, если считать, что mt < mj тогда и только тогда, когда i меньше / в обычном смысле. Этот порядок отражает, однако, не столько какие-то внутренние свойства элементов множества М, сколько свойства его нумерации и не исчерпывает других возможных способов упорядочивания. Поэтому понятия занумерованности и упорядоченности нужно различать. Аналогично наборам, для множеств используют символику, которая, обозначая само множество М, одновременно вводит обозначение для любого элемента т этого множества: Μ = {т} или (для счетных занумерованных множеств) Μ = {т,} (] = 1, . . .) и (для конечных множеств) Μ = {щ, . . . , тп).
58 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ В этом месте стоит также отметить разницу между занумерованными конечными множествами и наборами. Объект, являющийся компонентой набора, отличается от элемента множества тем, что он всегда воспринимается вместе с информацией о томг какой компонентой набора он является. В частности, набор может иметь несколько одинаковых компонент, а для множеств говорить о нескольких одинаковых его элементах не имеет смысла. Эти различия могут быть подчеркнуты примерами нескольких множеств, связанных с набором — вектором а = (ах = 1, а2 = 3, а3 = 1, а4 = 2), множество названий компонент {а1э а2, а3, а4}> множество названий компонент вместе с самими кохмпонентами: {(а1э 1), (а2, 3), (а3, 1), (а4, 2)}, множество значений компонент {1, 2, 3}. Наиболее близким к исходному набору является второе множество. Его даже можно было бы взять в качестве определения набора. Переменная и функция. Представление о множествах позволяет ввести нам еще одно фундаментальное математическое понятие — понятие переменной величины. Несколько упрощая трактовку, можно сказать, что это понятие употребляется в двух смыслах. В первом смысле переменная величина понимается как обозначение χ произвольного (любого) элемента некоторого множества X (X = {х}). Тот или иной элемент из X, связываемый с этим обозначением, называют значением переменной величины х» В другом смысле переменная — это некоторый абстрактный: объект, с которым в любой момент его рассмотрения может быть связан один некоторый элемент множества X, называемый его текущим значением. В этой второй трактовке переменная величина ближе к ячейке памяти ЭВМ, когда некоторый объект — переменная величина — является «хранилищем» другого объекта — своего текущего значения. В этой трактовке с понятием переменной связываются три обозначения, например, χ — для самой переменной, χ — для ее произвольного значения, являющегося элементом: множества X, которое называется областью задания переменной х. Употребление переменных величин в первом смысле можно- рассматривать как некоторую вольность, когда обозначения для: переменной и ее значений не различаются или же различаются по- контексту. Последнее, например, имеет место в алголе 60. В программе начало вещ х; ввод (χ); χ := χ + 1; вывод (χ) конец
§ 2.1. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКИХ ОСНОВ 59 нэрвое, второе и третье вхождение буквы # обозначает переменную геличину, четвертое и пятое вхождение обозначают ее текущее значение, а служебное слово вещ характеризует область задания х. Если в отображении F:X-+Y множество X является областью задания некоторой переменной величины х, то мы говорим о существовании функции F (х) аргумента х. Если χ — значение х, то F (х) называется значением функции F (χ), соответствующим указанному значению аргумента. В некоторых случаях имеет смысл говорить об отображениях S : Μ -+ Ν, хсогда соответствие между элементами Μ л N существует не для любых элементов М. Отображение S в этом случае называют частичным. Аналогично говорят ц о частичных функциях. Существует несколько стандартных процедур построения новых множеств из заданных. Пусть дан набор из η непустых множеств Мх = {тх}, М2 = {ль}» · · · ι Мп = {тп}. Прямым произведением, Mt X X М2 X ... Χ Μп, называется множество, элементами которого являются любые наборы вида (ти т2, . . . , тп)9 Если хотя бы одно из множеств Mt пусто, то, по определению, их прямым произведением будет пустое множество. Любое подмножество В прямого произведения двух множеств Μ = {т} и N = {п} называется бинарным отношением, заданным на множестве Μ Χ N. Элементы (т, п) множества В в этом случае называют парами, удовлетворяющими заданному бинарному отношению. Пусть даны два множества, Μ л N. Из них можно построить множества, которые называются объединением (M[JN), пересечением (M[\N) и разностью (M\N). Характеристическими свойствами, элементов этих множеств является их принадлежность: Μ или N — для объединения, как Ж", так и N — для пересечения, Μj но не N — для разности. Если N cz М, то M\N называется дополнением к N до Μ. Конструктивный объект. В математике часто выделяют объекты, построения и рассуждения, которые называют конструктивными. Это слово употребляют потому, что для такого рода объектов, построений и рассуждений хотят подчеркнуть дополнительное допущение, состоящее в том, что эти объекты можно взять и
60 ГЛ 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ рассматривать, построения можно выполнить, а рассуждения можно провести «эффективно». Конкретизация этого допущения в реальном мире означает, что осуществление любого из указанных действий должно быть выполнимо в конечное время и с использованием конечного количества материальных средств. В качестве исходных конструктивных объектов рассматривают лишь такие, в отношении которых признается бесспорным допущение об их элементарности и возможности всегда их рассматривать целиком. Для того чтобы контролировать эти свойства конструктивных объектов, для них всегда уточняется их представление, т. е. изображение с помощью ограниченного набора «поистине» примитивных объектов, которые считаются «атомами» всякого- объекта. Чаще всего в конструктивном подходе такими атомами являются элементы некоторого фиксированного конечного множества, называемого алфавитом. Сами элементы называются буквами. С каждым алфавитом связывается множество слов этого· алфавита. Каждое слово — это конечный упорядоченный набор букв, в котором мы различаем начальную букву, конечную букву, для каждой буквы, кроме начальной, ее левого соседа, и для каждой буквы, кроме конечной, ее правого соседа. Существует также пустое слово, не содержащее ни одной буквы. Число букв в слове называется его длиной. Практически, любые представления конструктивных объектов сводятся к их изображению в вида слов в некотором алфавите. Например, натуральные числа в тщательно написанных работах по конструктивной математике изображают словами в однобуквенном алфавите, так что число Пг изображается словом длины п. Какие бы то ни было соответствия или построения при конструктивном подходе считаются заданными или осуществимыми только в том случае, если они могут быть описаны в одном из принятых точных определений алгоритма, выполняющего действия над конструктивными объектами. В конструктивной математике рассматриваются бесконечные множества (например, натуральный ряд, множество всех слов в некотором алфавите), однако не допускаются никакие действия или рассуждения, которые используют принцип актуальной бесконечности. Элемент т множества Μ считается данным только· в том случае, если существует алгоритм, применение которого к другому уже данному конструктивному объекту позволит полу^ чить элемент т. Принцип потенциальной бесконечности позволяет нам считать данным любое натуральное число или любое слово в заданном алфавите. Утверждение о существовании некоторого объекта признается конструктивным, если оно опирается на алгоритм явного его построения. Такому доказательству противопоставляется косвенное рассуждение, когда из предположения о несуществовании та-
§ 2.1. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКИХ ОСНОВ 61 кого объекта приходят к противоречию (доказательство от противного). Граф. Мы закончим наш повторительный раздел описанием одной конструкции, которая будет постоянно использоваться в дальнейшем. Пусть дано конечное множество А = {аи . . ., ап}. Ориентированным графом G = (А, Г) называется набор из Л и любого бинарного отношения Г, заданного на прямом произведении А X А = {(аг·, aj)}. Элементы множества А называются вершинами, графа, а пары (at, aj)9 удовлетворяющие бинарному отношению, называются дугами графа. В дуге (ah aj) вершина а% называется предшественником своего преемника а^ Употребление таких слов как граф, вершины и дуги связано с геометрическим представлением бинарных отношений на плоскости или в пространстве, когда вершины изображаются точками, а дуги — стрелками, ведущими от предшественников к преемникам. С использованием ориентированных графов мы уже познакомились в предыдущей главе на примере операторных схем, где операторы были вершинами, а передачи управления — дугами. Пусть А* — подмножество множества А. Тогда подграфом G' графа G называется граф G' = (А', Г"), где бинарное отношение Г' = Т(~)(А' X А'). Мы видим, что Gr —это граф с вершинами А\ между любой парой которых проводится дуга в том и только в том случае, если эти вершины соединены дугой в графе G. Бинарное отношение Г, обладающее тем свойством, что если (at, aj)^r, то и (aj, at) ёГи (а.ь at) e (не принадлежит) Г, называется симметричным и антирефлексивным. Любое такое симметричное и антирефлексивное бинарное отношение Г задает неориентированный граф. Элементы множества А по-прежнему называются вершинами графа, а каждая пара (аг·, aj) и (а,·, at) из Г вместе называется ребром, соединяющим смежные вершины at к aj. В геометрическом представлении неориентированного графа на плоскости или в пространстве вершины изображаются точками, а ребра —линиями, соединяющими изображения смежных вершин. Как ориентированные, так и неориентированные графы будуг нами изучаться существенно глубже, однако, соответствующие определения нам будет лучше давать уже по ходу дела, сопровождая их поясняющими примерами. Автор опасается, что это краткое повторение математических основ при первом чтении не удовлетворит почти никого: подготовленный читатель найдет его слишком поверхностным, а начинающий — слишком коротким. Сознавая справедливость любой такой точки зрения, автор при работе над текстом неоднократно испытывал искушение отложить в сторону работу над этой книгой и написать другую, по основаниям математики, интересную для специалистов и поучительную для новичков. Дело в том, что безукс-
62 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ ризненное и свободное владение элементарными, но весьма глубокими принципами математического рассуждения необходимо далеко не только так называемым профессиональным математикам. Это не менее важно для тех, кто связан с применением математических методов на практике, с их реализацией на ЭВМ. Водораздел лмежду принципиальным и эффективным решениями, между конструктивным и неконструктивным подходами, между, абстрактным объектом и его представлением часто проходит по весьма тонким деталям математического исследования и должен тем не менее безошибочно ощущаться. В то же время зачастую фундаментальные основы математических построений и рассуждений излагаются мимоходом, рассеиваются по различным курсам или, вообще, считаются сами собой разумеющимися. Учитывая сказанное, автор счел необходимым затронуть основы математического исследования хотя бы в малом: дать краткую, но концентрированную сводку фундаментальных понятий в той степени, в которой они будут использоваться в книге, но не пожалеть времени и бумаги для методологических отступлений в тех местах основного изложения, где они покажутся уместными. Можно надеяться, что это разъяснит сущность введенных понятий для читателей, впервые знакомящимися с ними, и окажется небезынтересным для более продвинутых. § 2.2. Исходные определения Перечислим еще раз те понятия, которые мы ввели при содержательном анализе задачи. Это: операторная схема, оператор, аргумент, результат, величина, распределение памяти, граф переходов, маршрут, информационная связь, связка, несовместимость, граф несовместимости. Сейчас нам предстоит для каждого из них дать точные определения, в терминах которых мы будем искать решение нашей задачи. Определение операторной схемы. Исходным для нас является, по-видимому, понятие операторной схемы. Усвоив повторительный раздел, мы можем сказать, что основу операторной схемы составляет граф переходов, вершинами которого являются one-
§ 2.2. ИСХОДНЫЕ, ОПРЕДЕЛЕНИЯ 63 раторы, а дуги означают возможные передачи управления от одного оператора к другому. Каждый оператор имеет некоторое количество аргухментов и результатов. Распределение памяти состоит в сопоставлении каждому аргументу и результату имени некоторой величины. Совокупность всех имен величин — это та память, которая используется для передачи значений от результатов к аргументам. Придумывая определение для операторной схемы, мы должны сначала понять, будем ли мы определять любую, но одну схему, или множество схем. Это не совсем схоластический вопрос. Задать множество схем — это значит описать те «детали», исходные объекты, которые, свободно объединяясь друг с другом, создадут описываемое множество. Так, например, строится натуральный ряд, где исходными «деталями» является нуль и операция счета, которая для очередного числа «создает» следующее за ним по порядку. Более сложно, но аналогично, строится множество всех слов в некотором алфавите, множество идентификаторов в алгола и т. п. Эти аналогии, однако, не должны нас немедленно толкать на попытку дать грамматику всех возможных операторных схем. Есть древнее изречение: «не умножай сущностей без нужды», которое особенно важно в математике, где кажущаяся легкость умозрительных построений содействует этому необоснованному умножению сущностей *). Возвращаясь к нашему случаю, заметим, что мы не ответим на свой собственный вопрос, не продумав общие контуры и задачи нашей теории. Следуя Кантору, мы должны говорить о множестве объектов, если появляется определенная необходимость рассматривать их «все вместе» или хотя бы «любой из них». Посмотрим, как обстоит дело у нас? У нас есть задача — для заданной операторной схемы найти наилучшее допустимое распределение памяти. Это означает, что при решении задачи экономии памяти схема фиксирована, меняется только распределение памяти. Множество допустимых распределений памяти нам нужно обязательно — среди них нам нужно выбрать минимальное по числу используемых величин. Однако у нас нет необходимости сравнивать одну операторную схему с другой, которая отличается чем бы то ни было более существенным, нежели распределение памяти, даже если она решает ту же задачу (например, примеры 4 и 5 в главо 1) — мы сами вынесли такие сопоставления за рамки нашей теории. Таким образом, мы видим, что у нас *) Фольклор Московского математического общества хранит историю· об одном молодом докладчик е> который бойко начал свое выступление словами: «Без серьезного ограничения общности, мы можем рассматривать не белее, чем счетное множество». По ходу дела выяснилось, что он имел в* виду алфавит из двух букв.
64 ГЛ 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ нет необходимости строить множество всех операторных схем, -однако ее определение надо дать так, чтобы можно было бы для заданной операторной схемы рассматривать множество всех распределений памяти, определить среди них допустимые распределения (которые сохраняют информационные связи) и среди последних находить наилучшее. Итак, приступим к определению операторной схемы. Очевидное исходное множество — это конечное множество операторов F = {Fx, . . ., Fп). Теперь нам нужно определить их аргументы и результаты. Эти понятия у нас выступают двояко: во-первых, каждый из них относится к некоторому оператору, во-вторых, в разных распределениях памяти им сопоставляется та или иная величина. Эта общность функций аргументов и результатов дает основание объединить эти объекты одним общим названием. Как придумываются меткие названия и удобные обозначения — тайна творчества, которую не объяснить никакими книгами; мы их назовем вместе полюсами, по аналогии с входами и выходами электрической цепи. Нужно некоторое логическое усилие, чтобы увидеть полюсы сначала в виде отдельного множества объектов и лишь затем специальным отображением «приделанными» к тем или иным операторм. Резюмируя, имеем множество аргументов А = {αΊ, . . ., ар) множество результатов R = = {г1, . . ., rq}, которые объединяются во множество полюсов Ρ = A U R = {πχ, π2, · . ., яг}, где г = ρ + q. Распределение полюсов между операторами, очевидно, записывается в виде отображения V множества полюсов во множество операторов V : Ρ -> F. Граф переходов мы определяем как ориентированный граф С = (F, /), который строится на множестве F вершин-операторов и бинарном отношении /, задающем для оператора его непосредственные преемники по передаче управления. Построенные множества характеризуют нам схему, в которой ость все, кроме распределения памяти. Схема без распределения памяти — это еще не схема, но некоторая ее основа, скажем, скелет, на который и «наносятся» различные варианты распределения памяти. Итак, скелет S — это набор из множества операторов F, графа переходов С, множества аргументов А, множества результатов R и распределения полюсов между операторами V: S = (F, С, A, R, V). Для превращения скелета в схему нам нужна память — множество величин: X = {хх, . . ., хт} и распределение памяти среди полюсов, которое естественно задать в виде отображения
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 65 множества полюсов на множество величин L :Р-+Х (нам нет нужды рассматривать величины, не сопоставленные ни одному полюсу). Таким образом, операторная схема G— это набор из скелета S, памяти X и ее распределения L среди полюсов: G = (5, X, L). Займемся анализом полученного определения операторной схемы. Схема G строится по заданным произвольным конечным множествам абстрактных объектов: операторов F ={FX, ...,Fn}, полюсов Ρ = {пг, . . ., πΓ}, величин X = (х1У . . ., хт}, участвующих в построении графа переходов С и двух отображений — распределения полюсов V и распределения памяти L. Именно тот факт, что мы не фиксируем состав и свойства исходных абстрактных объектов, позволяет нам говорить, что мы не описываем множество «всех» операторных схем. Однако при заданных множествах операторов, полюсов и величин мы можем легко вообразить множество «всех» графов переходов С и отображений V и L. Спрашивается, можем ли считать операторной схемой любой набор ((F, С, Л, /?, V), Хч L4? Такой вопрос мы обязаны задавать себе при каждом введении правил построения какого бы то ни было составного объекта. При этом, как и в жизни, особенно тщательно нам нужно «заглядывать в углы», т. е. исследовать разные вырожденные и особые случаи, которые мы не имели в виду при содержательном анализе, концентрируя свое внимание прежде всего на «типичных» ситуациях, но которые, естественно, необходимо исследовать, вторгаясь в сферу неограниченной комбинаторики формальных определений. На самом деле контроль над общностью определений составляет постоянную часть математического исследования, которая завершается только после тщательной проверки всех этапов работы. Чисто эстетические критерии простоты и стройности побуждают математика выдерживать уровень общности, пока он не столкнется с противоречащим примером или окажется не в состоянии построить доказательство из-за трудности задачи. С другой стороны, он должен без колебаний расставаться с «пустыми» обобщениями, которые, ничего не добавляя к нашему знанию, делают изложение утомительным, а алгоритмы громоздкими. В нашем случае анализ определения операторной схемы на общность тоже будет носить предварительный характер, касаясь анализа графа переходов, распределения полюсов π памяти.
66 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ Анализ понятия графа переходов. По определению граф переходов — это произвольный ориентированный граф с вершинами F = {Fx, . · ., Fn}. Может ли программа иметь произвольный граф своим графом переходов? У нас есть, конечно, под влиянием г) В) ?ис. 2.1. Примеры графов. упорядоченной логики программирования ходячее представление о «типичной» программе, к которому, несколько пофантазировав, мы добавляем некоторую коллекцию менее обычных графов, представленных всех вместе на рис. 2.1.
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 67 Прежде чем обсудить по существу разнообразие этих картинок, дадим несколько определений и свойств, которые позволят нам вести обсуждение более четко и, кроме того, пригодятся в дальнейшем. Приведенные примеры графов делятся на две категории: в одной из ηρϊχ, а) и в), графы изображены в виде «связных» фигур, в другой, б) и г), четко распадаются на изолированные друг от друга, но связные «внутри |Себя» части. Наконец о д) мы затрудняемся сказать что-либо определенное. Разберемся в этом подробнее. Свойство связности состоит в том, что какие бы две вершины связного графа мы не взяли, существует путь из дуг, соединяющих эти вершины. Для интуитивного представления этих слов достаточно, но нам нужпы более точные определения. A. Две вершины в графе называются соседними, если одна из них является предшественником другой (или они смежные — для неориентированных графов). Б. Две вершины, а и Ь, в графе называются связанными, если существует последовательность вершин графа их, v2, . . ., vn, такая, что v± = a, vn = b и любая пара (vt, vi+1) (i = 1, # . . . . . , η — 1) образована соседними вершинами. B. Граф называется связным, если в нем любая пара вершин является связанной. , Пусть нам даны два графа, Gx = (Ах, I\) и G2 = (Л2, Г2). Очевидно, что пересечение ГХГ|Г2 будет подмножеством прямого произведения (А1ПА2)Х(А1ПА2). Граф G' = (АХС)А2, ГХПГ2) называется пересечением графов Gx и G2: Gr = G^flG^. Аналогично определяется объединение графов Gx [} G2. По определению, граф называется пустым, если пусто множество его вершин. Наконец два графа называются непересекающимися, если пусто ;/их пересечение. Смысл этих определений станет ясным, когда мы сформулируем простую, но замечательную теорему: Теорема 1. Любой непустой граф G можно однозначно представить в виде объединения непустых попарно непересекающихся связных подграфов Gx, . . ., Gx (Z^ 1). Доказательство. Опишем следующую однозначно выполняемую процедуру. Пусть граф G образован вершинами ах, . . ., ап. Построим для каждой вершины at (i = 1, . . ., η) множество Dt связанных с ней вершин. В результате мы получим η множеств /)1? . . ., Dn. Покажем, что для любой пары Dt и Dj либо Dt = Dj, либо Dt {]Dj = 0, где 0 — введенный ранее символ пустого множества. Сначала докажем лемму. Лемма. Если в графе две вершины а и Ь каждая связаны с вершиной с, то они связаны друг с другом.
68 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ Действительно, но определению связности есть две цепочки соседних вершин: а = vv v2, . . ., vn = с и Из них можно составить одну цепочку α = ι?ι, ^2> · · ·» уп = с = ит, . . ., и2, i^ = b, которая доказывает связанность а и Ъ. Вернувшись теперь к множествам Dt иС/, сразу устанавливаем, что если at и α7· связаны, то, во-первых, каждая из них входит как в Di9 так и в Dh и любая вершина, связанная с одной из них, будет связанной и с другой, т. е. в этом случае Dt = Dj. Если же at и α7· не связаны, то Dt и Dj не могут иметь ни одной общей вершины, так как если бы такая вершина Ъ существовала, то из связанности аг· с Ъ и а7- с Ъ следовала бы связанность at и а7г что противоречит допущению. В результате у нас получилось однозначное разбиение множества А = {а19 . . ., ап) на некоторое количество попарно пересекающихся множеств В19 В2, . . ., Вг. Построим для каждого из Bt (i = 1, . . ., Ζ) подграф Gt графа G, имеющий Бг- своими вершинами. По определению подграфа такое построение также однозначно, при этом также очевидно* что полученные графы попарно не пересекаются.. Осталось показать, что G = G1[iG2[i. . . U6|. Мы уже показали, что а = вгив2и... иЯ|. Пусть Г — множество дуг графа С и Г{ (i = 1, . . ., Ζ) — то же для графа Gt. Покажем, что г = г1иг2и... и г,. Так как Gt —- это подграфы графа G, то г^г.и... игг^г. Докажем обратное включение. Наждая дуга графа Г либо принадлежит одному из подграфов Git либо соединяет вершины,, принадлежащие разным подграфам, например, a^Gt и beG/. Этот случай, однако, невозможен, так как если бы α и & оказа- лись'соседними вершинами, то в силу леммы и свойств множеств Вг и Вj любая вершина из В% оказалась бы связанной с каждой из вершин Bj, что в силу построения Вг и Bj возможно, только если Bi = Bj, что также противоречит их попарной непересекаемос-
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 69 ти. Теорема доказана (что в дальнейшем мы будем отмечать двумя «наблами» VV» оставляя одну «наблу» V Для признака окончания доказательства леммы). Графы Gx, . . ., Gx из формулировки теоремы называются компонентами связности графа бч Продолжим рассмотрение примеров графов с рис. 2.1. Итак, мы видим, что в общем случае граф переходов может состоять из нескольких компонент связности. Даже не дождавшись построения общей теории, мы можем немедленно заметить, что если операторная схема распадается на изолированные части, представленные компонентами графа переходов, то в каждой части экономию памяти можно проводить раздельно, так как величины, относящиеся к разным частям, заведомо совместимы друг с другом. С этой точки зрения естественно потребовать, чтобы граф переходов был связным. С другой стороны, можно представить себе реальную ситуацию, в которой объектом экономии является комплекс программ, с заранее не известным строением, например, полученный с помощью транслятора или просто слишком сложный, чтобы разбираться заранее, сколько компонент связности в графе переходов (рис. 2.1, д)). Тогда нам может оказаться более выгодным иметь одну процедуру экономии памяти, которая сделает свое дело, не вовлекая нас в анализ графов переходов. Оказавшись перед лицом этих противоречивых факторов, мы фиксируем возможную полезность разбиения, или, как говорят, факторизации экономии памяти по отдельным компонентам графа переходов, но развиваем теорию для общего случая столь долго, сколько это окажется естественным. Сравнивая «типичный» граф переходов с рис. 2.1, а) с другими примерами, мы усматриваем такие особенности, как одно- операторные компоненты (2.1, б)), графы без заключительного и без начального операторов, графы с несколькими начальными или несколькими заключительными операторами. Практика программирования подсказывает нам, что эти особенности, вообще говоря, не должны быть объектом априорных ограничений. Случай нескольких начальных или заключительных операторов уже должен быть предусмотрен хотя бы из допущения нескольких компонент связности. Наконец, бывают такие программы, которые либо не имеют команд останова или имеют вместо них команду паузы, допускающую продолжение работы — это делает приемлемым случай рис. 2.1, в). Одним словом, мы сохраняем пока что определение графа переходов во всей его всеобщности. Распределение полюсов. Продолжим наш анализ определения операторной схемы с распределения полюсов V : (A U R) -> F.
70 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ Мы уже освоились с мыслью, что оператор может иметь любое число как аргументов, так и результатов (в том числе и равное нулю). Допущение произвольного Сможет, однако, привести к таким схемам, в которых входной оператор будет иметь аргументы (которые нечем загружать) или выходной оператор — результаты (которые негде использовать). Другими словами, у нас могут получаться «бессмысленные» операторные схемы. Как нам к этому относиться? Как обычно, ответ на этот вопрос дают не в меньшей степени общие соображения, нежели специфика задачи. Уже повседневная практика подсказывает нам, что любая формальная конструкция всегда создает объекты «с запасом», по отношению к которому «осмысленные» объекты образуют подмножество. Такой запас, например, создают грамматические правила русского языка, да и не только его, но и любого языка программирования, того же алгола. Существование такого запаса не случайно. Во-первых, смысл, т. е. связь абстрактного объекта с явлениями реальной ^жизни, есть, строго говоря, категория, находящаяся за рамками математического рассуждения· Можно давать, конечно, формальное определение смысла, или, как говорят, интерпретацию объекта и проверять его выполнимость. Такой подход существует, и мы в этой книге еще коснемся вопросов интерпретации, в том числе и для теории, развиваемой в этой главе. Во-вторых, описание смысла, даже если оно и предпринимается, сильно усложняет теорию, не давая иногда каких-либо заметных преимуществ. Одна из причин сложности состоит в том, что смысл не зависит целиком от состава объекта, не определяется им самим, а требует учета какого-то более широкого контекста, описать который κθ всегда возможно. Услышанная как-то автором фраза: «Вчера клево побалдели с хипарями в одной кодле», рез сомнения, вполне понятна кому-то из молодых читателей, но для других будет таким же экзотическим словосочетанием, как знаменитый пример А. В. Щербы: «Глокая Куздра штеко будланула бокра»,— фразы, грамматически безупречной, но бессмысленной. Природу другой сложности нам можно будет пояснить и на материале нашей задачи. Скажем, нам не нравится, что конечный оператор может иметь нигде не используемые результаты. Мы второпях напишем: «Распределение полюсов должно удовлетворять условию, чтобы конечный оператор не имел результатов». По принципу, сказав А, говорить и Б, мы должны будем, по- видимому, рассмотреть, описать и запретить другие случаи употребления операторов с неиспользуемыми операторами. Предположим, что нам удастся это сделать. Однако тогда нам надо будет реагировать на требования другого рода. Предположим (это практический пример), что в ЭВМ есть команда вычисления целой части числа, вырабатывающей при этом и дробную часть.
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 71 которая также автоматически отправляется в память. В таких случаях, хочешь не хочешь, мы должны допускать наличие операторов с неиспользуемыми результатами и теория должна рассчитывать на такую возможность. Но уж если мы «выпустили джина из бутылки», то зачем нам ограничение на результаты заключительного оператора, если оно не будет «работать» в теории. Мы позволили себе отвлечься от основной нити рассуждения потому, что хорошее понимание разницы между формальными и «осмысленными» объектами для недостаточно опытных специалистов, занятых постановкой прикладной-задачи, иногда является источником больших трудностей. Над ними довлеет предрассудок, что чем конкретнее, чем прицельнее определение, тем правильнее, тем осмысленнее теория. И здесь, так же как и в случае чрезмерных обобщений, единственным методологическим критерием является постоянный логический контроль теоретических рассуждений и конструируемых алгоритмов на предмет того, чтобы любая общность использовалась до конца и, наоборот, любое ограничение использовалось бы по существу. Итак, мы принимаем определение распределения полюсов без каких-либо ограничений. Распределение памяти. Рассматривая последнее отображение L : Р-+Х, читателю под влиянием прочитанного захочется сохранить его в полной всеобщности. Тем не менее нам все равно надо постараться вообразить возможные «особые» случаи в распределении памяти. Произвольное распределение памяти может, в частности, создавать возможности «незамкнутости» информационных связей вдоль каких-либо цепочек операторов, т. е. незаданных аргументов и неиспользованных результатов. Мы уже знаем из только что приведенного примера одновременного вычисления целой и дробной частей числа, а также из более раннего примера 11 (гл. 1),что такая ситуация может создаваться наличием «избыточных» результатов и «необязательных» аргументов, а также неразличением на операторной схеме допустимых и недопустимых цепочек операторов. Таким образом, поскольку предотвратить кезамкнутость информационных связей мы не можем, нам нет необходимости и пытаться ограничивать распределение памяти с этой стороны. Наконец, в распределении памяти может быть еще одна особенность: нескольким аргументам или нескольким результатам одного оператора сопоставляется одна и та же величина. Эта особенность требует определенного исследования. Начнем с результатов.
η ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ Когда мы характеризуем множество распределений памяти, фигурирующих в определении операторной схемы, мы должны, естественно, иметь в виду не только те распределения, которые задают исходную схему, но и те, которые можем иметь в виду в поисках максимальной экономии памяти. С этой точки зрения мы знаем наперед, что распределение памяти, сопоставляющее ранее разноименным результатам оператора одну и ту же величину, будет заведомо недопустимым (простейшие примеры, иллюстрирующие наши рассуждения, показаны на рис. 2.2). Действительно, если слияние имен результатов не будет сопровождаться слиянием имен аргументов (рис. 2.2, б)), то мы по формальным X f xk ъ у ■Т fx X § \ <pff ю $) ι ху Л ι \ 1 \ ! 1 1 / \1 XU 9 х /| ι Ι / 1 ( ! \ I \ I V| 1 *>·* 1__ «2? ^ ?ί±ι Ъ 8) г) Рис. 2.2. Простейшие примеры некорректных переименований. признакам будем иметь потерю информационной связи, что недопустимо. Если же слияние будет сделано согласованно, то мы, формально не нарушая принципа сохранения информационных связей, не сможем тем не менее их разумно интерпретировать, так как для каждого аргумента не сможем знать, какой результат явился отправителем используемого значения величины. Очевидно, что та же неопределенность создается, когда слияние имен имеет место в исходной схеме. Правда, мы можем попытаться дать специальную интерпретацию такому слиянию: считать, что в этом случае оператор таков, что значения результатов, которым сопоставлена одна величина, получаются всегда одинаковыми, что и позволяет их без противоречий считать за одну вэличину. Эта оговорка спасает теорию, но, как видите, требует специального толкования. Наше дело решить — что удобнее. Автор полагает, что читатель согласится с его предпочтением наложить ограничение на распределение памяти: если rt Φ г7· и V(rt) = V(rj), то L(rt) Φ L(rj). Рассмотрим теперь слияние имен для аргументов. Наличие двух аргументов с одной и той же величиной в операторе, в отличие от случая результатов, особой интерпретации не требует. Правда, мы знаем, что при любых распределениях памяти теория предпишет нам всегда эти два аргумента помечать одной ве-
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 73 личиной; поэтому, казалось бы, при переходе от программы к схеме мы могли бы без ущерба для дела считать эти два аргумента за один, полагая тогда, что разные аргументы тоже имеют разные величины. Однако прежде чем формулировать соответствующее ограничение, нам надо проверить, не будет ли слияние имен аргументов допустимым распределением. Немного поразмыслив, мы можем придумать схему, изображенную на рис. 2.3, а), в которой информационные связи по всем формальным х Ч \ / Р# Ю δ) Рис. 2.3. Слияние имен аргументов. признакам оказываются совместимыми, что вполне позволяет сопоставить обоим аргументам оператора F4 одну и ту же величину (рис. 2.3, б)). Этот пример, правда, может показаться кому- нибудь неубедительным, так как он допускает незамкнутые информационные связи: приходя к F4 по цепочке F1F29 мы имеем аргумент у неопределенным. Мы в этом случае сошлемся на уже состоявшуюся дискуссию о приемлемости незамкнутых связей даже вдоль допустимых структурой схемы цепочек операторов. В частном случае, здесь работает такая интепретация (опять взятая из реальных ситуаций): оператор FA «знает», по какой цепочке -к нему приходит управление и работает именно с задействованным аргументом, не используя другой, оставшийся неопределенным. Таким образом, мы не накладываем каких бы то ни было ограничений на распределение величин среди аргументов. Разобравшись с определением операторной схемы, нам теперь надо дать точное определение совокупности информацион-
74 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ ных связей как того инварианта схемы, сохранение которого является требованием допустимого распределения памяти. Для описания этого инварианта нам придется иметь дело с операторами и их цепочками в графе переходов, аргументами, результатами и сопоставленными им величинами. Для всего этого нам надо будет ввести дополнительные обозначения и термины, которые будут точными и строгими понятиями, согласованными с обозначениями, использованными при определении операторной схемы. В этом месте нам будет уместно снова несколько отвлечься и поговорить вообще о некоторых принципах математической терминологии и символики. Отступление о терминах. Необходимость строгих определений и точных обозначений — это первое, к чему привыкает начинающий математик. Гораздо труднее дается искусство сочетания строгости и точности с простотой и ясностью при написании математической работы. Эта трудность усугубляется тем, что сейчас основной формой публикации оригинальных математических работ являются журнальные статьи, в которых, как правило, ограничения, на объем являются главным фактором, определяющим стиль изложения. К вопросу о том, как преодолевается эта трудность, мы еще вернемся, а сейчас сделаем только два отступления: об использовании содержательной терминологии и об индексомании. Термин — это или исконное слово языка публикации, или слово, внесенное в язык автором, используемое для обозначения абстрактного объекта или его свойств. Например, «множество» и «сепарабельный» — термины первого и второго типа соответственно. Заметим, что в математике между термином и символическим обозначением нет никакой принципиальной разницы. Мы можем сказать: пусть F — непрерывная функция и потом использовать только символ F, не произнося слово «функция». С другой стороны, любой символ, используемый в тексте, при аккуратно проведенном грамматическом разборе, играет роль вполне определенного члена предложения. Не случайно в заботливо написанных учебниках всегда даются правила для «чтения» символических выражений, в которых грамматическая роль обозначений выступает в явном виде. С этой точки зрения особенностью математического термина является то, что он употребляется исключительно в смысле, приданном ему в определении, т. е. в задающей его фразе. Когда мы говорим о «простом числе», мы должны всегда помнить, что мы в этот термин не вкладываем ничего другого, кроме того, что оно с^тлично от единицы и имеет в качестве своих делителей только единицу и самого себя* В то же время подавляющее большинство слов родного языка, активно усвоенных читателем, всегда являются носителями всяких «других» смыслов, заложенных в них самой реальной
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 75 жизнью языка. Мы говорим о множестве целых чисел и о множестве людей, о функции Вейерштрасса и функциях руководителя, о группе движений в евклидовом пространстве и профсоюзной группе. Человек даже с хорошо развитой способностью к логике не в состоянии отмежеваться от этих «других» смыслов, проникающих ему в подсознание и формирующих представление о термине помимо его воли *). Это обстоятельство породило традицию использования в качестве терминов незанятых слов, главным образом иноязычных, ничего не говорящих чужому уху и доступных для «заполнения» их смыслом, устанавливае- мым автором. Традиция, кроме того, подкреплялась многовековым употреблением латыни в качестве языка научной прозы. Вот почему в математической литературе так много «эпициклоид», «факториалов»; «трисектрис», «кватернионов», «асимптот» и прочих звучных слов, создающих внешний наряд профессиональной литературе, Этот внешний наряд, к сожалению, создает иногда превратное представление о сущности научного литературного стиля **). Не надо думать, что образные (т. е. имеющие дополнительный, наглядный смысл) термины противопоказаны математике. Они, во-первых, напоминают математику природу реального объекта, стоящего за определяемым этим термином формальным объектом. К этой категории относятся, например, такие термины, как «волновая функция», «игра» (из теории игр), «потенциал», «высказывание» (в математической логике), «ожидание» (в теории вероятностей) и т. п. Другую категорию (наиболее многочисленную) составляют образные термины, которые благодаря выбранному слову создают именно образ,ацюжде всего зрительный, определяемого объекта или слова: «кривизна», «непрерывный», «касательная», «луночка», «ребро» (в графе), «дерево», «маршрут» (в этой книге) и многие другие. Наконец, следующую категорию *) На защите дипломных работ в Новосибирском университете студент, говоря о разбиении некоторого конечного множества Μ на подмножества, упорно называл последние «группами элементов множества Л/». Это, казалось бы, безобидное словоупотребление, оказалось совершенно неприемлемым для одного из членов комиссии, глубокого специалиста по теории групп. Его естественное стремление немедленно увидегь единицы, обратные элементы и прочие атрибуты этого емкого понятия затрудняло восприятие доклада. Студент был тоя^е не в состоянии перестроиться, и тот минимум взаимопонимания, который необходим для успешной защиты, так и не был установлен. **) Продолжая нашу серию подстрочных историй, нельзя не вспомнить иронического замечания одного из лучших лекторов нашего времени академика С, Л. Соболева, сделанного им на семинаре в Вычислительном центре Московского университета по поводу употребленного докладчиком термина «вызыватор». ^Этим термином автор обозначил управляющую программу, производящую вызов модулей большого программного комплекса. Смысл замечания был очевиден: нельзя ради ложного наукообразия коверкать язык и приделывать к исконному русскому слову латинский суффикс.
7G ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ образности составляют термины, которые в самом языке используются как абстрактные понятия, созвучные их употреблению в математическом тексте: «множество», «вероятность», «мера», «объединение», «дополнение», «связность», «расстояние», «вес» и т. п. Образная сторона терминологии является, тем самым, могучим средством сделать изложение более эффективным в том смысле, что читатель не только поймет и усвоит логическую структуру текста, т. е. удостоверится в правильности доказаг тельств, но и, что гораздо важнее, обогатит свою интуицию, установит связи изученного^математического текста со своим опытом и ранее приобретенными знаниями. Заключая свое отступление о терминологии, автор желает поощрить употребление образной терминологии с обязательным выполнением следующих условий: — термин должен быть точно определен в математическом смысле; — образная нагрузка термина не должна быть случайной, а быть тщательно отобранной с учетом сделанной классификации образности; — надо избегать в статье неформальных рассуждений, использующих те же слова, что и введенные термины, но в их обыденном смысле; — необходимо уважать сложившуюся «занятость» термина в литературе, которая считается известной предполагаемому читателю; — создание терминов считается таким же почитаемым вкладом в науку, как и доказательство теорем, являясь тем самым объектом признания приоритета, цитирования и других требований научной этики. Отступление об индексах и символах. Рассмотрим теперь признаки индексомании — распространенной детской болезни начинающих авторов. Употребление индексов имеет под собой два объективных основания: — нумерация однородных элементов конечного множества является удобным средством их различения, сохраняя в то же время однотипность обозначений, подчеркивающую эту однородность; — применение арифметических действий к натуральным числам, нумерующим элементы множества или компоненты набора, позволяет компактно записывать сложные манипуляции с нумеруемыми объектами. Трудность, однако, состоит в том, что обычно нумерация '-элементов некоторого множества считается зафиксированной в пределах всего рассмотрения (статьи, главы и т. п.) и, поэтому, если вы определите где-нибудь, что множество Μ = {тг, τη%γ . . ·> wfe}, то, скажем, т2 или mk будут, естественно, всегда
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 77 ъосприниматься, как именно второй и последний элемент описанного множества. К чему это приводит, покажет следующий пример. Читателю предлагается взглянуть на страницу, которую он читает в данный момент. Она образована буквами из алфавита {а1у . . ., αη}. Мы занимаемся проблемой автоматического набора текста с помощью ЭВМ. Для этого нужно каждую букву текста заменить номером отделения в наборной кассе, по которому машина выберет нужную букву. Предположим, далее, что мы набираем наш текст наподобие поэтического с точным соответствием рукописных строк печатным. Тем самым для каждого вхождения буквы в текст задается его позиция: номер строки г и номер буквы в строке у\ а в позиции (i, j) находится номер п^ соответствующей буквы, так что сама буква будет, стало быть, выглядеть, как ап... Число букв в каждой ΐ-й строке, естественно, свое, пусть оно будет kt. Пусть далее на странице имеется т абзацев, и номера ст.рок, начинающих их, будут it, i2, . . ., im. Пусть, наконец, правила набора таковы, что для того, чтобы некоторая строка начиналась с абзаца, необходимо, чтобы последняя буква предыдущей строки была бы каким-нибудь специальным управляющим символом, скажем, ф. Тогда, если вам надо будет точно сформулировать условие правильной разметки абзацев в вашей странице, это будет выглядеть в виде следующего многоэтажного сооружения (для г = 1, ..., т) an.r__ihi _χ = #. Иидексомания состоит не в том, чтобы «обожать» такие выражения, а борьба с ней заключается не в искоренении индексов. Приведенная выше лестница индексов может совершенно законно быть использована в какой-нибудь программе машинного набора текстов. Беда в том, что авторы иногда не знают, когда индекс необходим по существу, а когда их можно опускать и можно ли их опускать вообще. Одна из причин трудностей состоит в уже упоминавшейся путанице между нумерациями множеств в целях упорядочивания, в целях обозначения или в целях пересчета их элементов. Употребление индекса неизбежно только тогда, когда вам надо говорить о всех элементах множества или подмножества, которые вы просто не сможете обозначить единым способом, не введя пересчитывающего их индекса. В тех же случаях, когда вы, осуществив акт произвольной выборки, говорите «пусть т% — некоторый элемент множества М*9 вы можете вместо rrti взять любое родственное обозначение элемента, не имеющее индекса. Такими родственными обозначениями могут быть символ элемента без индекса тю, этот же символ со штрихами т', т" и т. п. и, наконец, близкие по алфавиту
78 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ буквы (с такими привычными для глаза сочетаниями знаком каждый: (а, Ь, с), (/, g, h), (ί\ /, к), (т, п)у (р, q, г), (и, υ), (χ, у, ζ> и т. п.). Внесение такого разнообразия в символику требует, однако,. от пишущего хозяйского, аккуратного отношения к алфавиту к соблюдения некоторых норм, носящих как эстетический, стилистический, так и логически обязательный характер. Обозначения в математических текстах, так же как имена в программах на алгоритмических языках, подчиняются точным правилам локализации, устанавливаемой с помощью задающих фраз. Как правило, большинство обозначений локализуются в пределах весьма небольших порций текста: формулировка теоремы, абзац, логический этап в доказательстве. Четкое использование задающих фраз позволяет одновременно и экономить обозначения и, наоборот, приучать читателя к глобальным обозначениям и объектам, фиксируемым на значительном протяжен нии изложения. При выборе обозначений надо учитывать формально необязательную, но фактически сложившуюся иерархию алфавитов и букв, отражающую иерархию построения объектов: малые буквы для исходных абстрактных объектов, заглавные буквы для «простых» составных объектов и множеств, полужирные заглавные буквы для занумерованных наборов и множеств, прописные буквы для наиболее объемлющих объектов, классов множеств и т. п. Конечно, многие более узкие разделы математики имеют собственную шрифтовую стилистику. Так же как и в терминах, следует избегать «занятых» обозначений и стараться не обозначать, скажем, буквой iV, которое у большинства ассоциируется с натуральным рядом, какое- нибудь множество функций или вещественных чисел. Если же приходится использовать такие «избитые» буквы, как х, F, η и т. п., то либо не бойтесь показаться неоригинальным и связать с χ — неизвестную, с F — функцию, а с тг — целое число, либо используйте их для Точно заданных, но мимолетных использований с тем, чтобы отзвук только что сказанной задающей фразы предотвратил бы на короткий срок привычное восприятие символа. При прочих равных условиях не умножайте без нужды алфавит используемых символов. Подготовка математических текстов для печати сейчас становится массовой и рядовой работой г при этом далеко не только в специальных типографиях, но и в огромном количестве в институтских и отраслевых изданиях, безнаборным способом, с подготовкой текста на ЭВМ и в других стесненных, но зато обеспечивающих оперативность обстоятельствах. Латинский шрифт одной гарнитуры — это ваш прожиточный минимум; добавление греческого алфавита, полу-
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 79 мирной и рукописной гарнитур должно вас обеспечить для труда любой сложности. Точное определение несовместимости. Вооружившись сделанными стилистическими замечаниями, приступим к разработке терминологии д символики в интересах нашего исследования. Существенно большей гармоничности мы сможем добиться, если попытаемся разработать символику одновременно и заблаговременно; тот факт, что мы уже очертили контуры теории при содержательном анализе задачи, . позволяет нам это сделать. Конечной конструкцией теории экономии памяти является граф несовместимости. Введем для него обозначение, скажем, U. Выбор обозначений — это комбинация случая, трациций, а иногда некоторого тайного умысла автора, не обязательно сообщаемого читателю. Работая с латинским алфавитом, мы иногда будем иметь в виду заглавные буквы различных английских слов, имеющих отношение к делу. Мы уже использовали слова argument (аргумент), result (результат), pole (полюс) в обозначениях A, R и Р. В данном случае мы используем слово uncompatibility {несовместимость). Вершины графа U — это «связки» информационных связей. Связка — это пока что не описанный точно объект, представляющий собой некоторое подмножество связанных друг с другом информационных связей операторной схемы. Информационная связь — это пара полюсов (г, а), которым сопоставлена одна и та же величина и для которой существует хотя бы один реализующий эту связь маршрут. Маршрут — это некоторая последовательность^вершин графа переходов, которая может быть «пройдена» по д^гам этого графа. Для определения маршрута нам нужно определение «пути» в ориентированном графе и обозначения4-для его начальной, конечной и внутренних транзитных вершин. Кроме того, для операторов, образующих маршруты, нам нужны обозначения их аргументов и результатов. Для определения допустимого распределения памяти нам нужно рассматривать множество всех маршрутов всех информационных связей. Оно заслуживает отдельного названия — его естественно назвать носителем (информационных связей) и. обозначить CR (carrier). Для построения графа U нам нужно задать бинарное отношение несовместимости на связках. Это отношение, как вы помните, зависит от взаимного расположения маршрутов, реализующих информационные связи из связок (начало одного маршрута оказывается транзитом или тоже началом другого). Все перечисленные конструкции очень просты, и значительную часть из них мы только что мимоходом определили, однако даже на этом материале мы можем продемонстрировать разный подход к определению понятий.
80 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ Начнем с определения пути в графе. Пусть дан граф G=(A, Г), где А = {ях, . . ., ап} — множество вершин и Г — множество дуг. Путем в графе G называется последовательность вершин такая, что (а^., aij+1)^ Г для всех / = 1, . . ., η — 1. Об этом можно сказать и по-другому. Путем в графе G является любая' конечная последовательность W вершин графа длины не менее двух, такая, что любая вершина из W (кроме последней) является в G преемником предыдущей вершины из W. Каждое из этих определений одинаково точно, имеет ^вси преимущества и недостатки. Первое требует введения * обозначения вершин, индексов. Второе определение не исцользует индексов и символики, но опирается на свойства последовательности (наличие следующего элемента, понятие длины последовательности) и определение преемника. Выбор между одним и другим подходом к определению и определяет стиль изложения в работе. Каждый из них «законен», но этот пример показывает, что символика не всегда сокращает изложение и не всегда делает его более понятным. , Определим теперь понятие маршрута. Продолжая стилистику символизированного изложения, мы скажем: маршрутом информационной связи (г, а) называется любой такой путь в графе переходов, что L(r) = L(a) = χ, V(r) = Ft , V(a) = = Fik и для любого г', такого, что V(r') = Ft. (j = 2, . . ., к — 1), L{r') Φ χ. Для сопоставления дадим другое, «словесное» определение маршрута. Перед этим дадим еще два определения, которые нам пригодятся и в дальнейшем. Любая вершина, входящая в позицию некоторого пути в графе, отличную от начальной и конечной вершин пути, называется транзитной. Оператор воспринимает (вырабатывает) величину х, если он имеет аргумент (результат), которому распределением памяти сопоставлена величина х. Маршрутом информационной связи (г, а) называется любой такой путь в графе переходов, что его начальный оператор вырабатывает х, сопоставленную г, конечный оператор воспринимает х, сопоставленную а, и ни один из транзитных операторов не вырабатывает х. Проанализируем сделанпое определение. Во-первых, понятие маршрута включает в себя не только путь в графе переходов, т. е.
§ 2.2. ИСХОДНЫЕ ОПРЕДЕЛЕНИЯ 81 некоторую последовательность операторов, но и информационную связь, которую этот путь реализует. Таким образом, на а) J7T7I χο 1 оу Хох \ 9У 3 \ТУ$д \ *~? ч /Ч^К^ -47" \*\]Г\-' Ε У ~л Χ ,-, ~~HzJ—Ηе 1 /4 δ) ! ι ι 3 f :ϊψ № ' ! R 1 ' X 1 ' IP ъ f 1 h b # <?; Рис. 2.4. Примеры маршрутов информационных связей, а) Граф переходов с двумя маршрутами, б) Граф с бесконечным числом непериодических маршрутов, реализующих информационную связь, в) Граф переходов с двумя областями действия величины х. г) Граф переходов, в котором при объединении χ и у сохраняется информационный граф, но пропадает маршрут. рис.2.4, а) операторная схема имеет два маршрута. Это значиг> что маршрут должен изображаться как набор из двух компонент: пара полюсов (результат, аргумент), образующая информационную
82 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ II ОБЩАЯ ТЕОРИЯ связь, и реализующий ее путь. Для схемы с рис. 2.4, а) это будет (а, с), ЛВС и (Ь, d), ABC. Во-вторых, надо понимать, что хотя информационных связей в операторной схеме может быть не больше pXq, где ρ — число аргументов, a q — число результатов в схеме, количество {маршрутов, реализующих одну и ту же связь, может быть бесконечным. Рис. 2.4,6) с очевидностью показывает причину этому: наличие циклических путей, например, В С DO Ε F В. Цикличность графа наводит на мысль о периодичности путей, однако даже примера рис. 2.4, б) достаточно, чтобы показать, что множество путей никакой периодичности может и не удовлетворять. Возьмем любое двоичное число, и для каждого его разряда d повторим один раз цикл операторов ВС qaEF; при этом, если а = 1, пройдем по ветви с 2)1, а если d=0, то по DO. Пример рис. 2.4, в) показывает, почему требование не вырабатывать величину, через которую осуществляется информационная связь, не накладывается на конечный оператор маршрута. Это соответствует содержательной интерпретации понятия оператора, который при выполнении сначала воспринимает значение аргумента, а потом вырабатывает результат. Поэтому создание нового значения χ оператором D не мешает реализоваться связи от Л кА. Восприятие значения аргумента не уничтожает это значение, поэтому оператор С, являясь конечным для маршрута от Л к С, оказывается транзитным в маршруте от А к D. Пример рис. 2.4, г) демонстрирует другой источник множественности маршрутов, реализующих одну и ту же связь,— наличие ветвлений в графе переходов. Каждый из путей создает свой маршрут за исключением ABCDEH, в котором оператор D прерывает возможные связи А с Ε и Н, создавая «свои» маршруты DE и DEH. Дав точное определение маршрута как конструкции, овеществляющей информационную связь, мы автоматически приходим к понятию носителя CR как множества всех маршрутов операторной схемы. Заметим, что хотя маршруты строятся по заданной операторной схеме, т. е. скелет + память + распределение памяти, сам носитель состоит из конструкций, построенных только из элементов скелета (операторы и полюсы). Это важное свойство носителя позволяет сравнивать носители схем с одним скелетом, но с разными X и L. Если носитель CR строится по схеме G, то чтобы подчеркнуть эту зависимость, мы будем обозначать носитель CR(G). Теперь мы можем дать следующее
§ 2.3. ОБЩАЯ ТЕОРИЯ 83 Определение. Пусть даны две операторные схемы G = = (S, X, L) и & = (S, X', L). Мы скажем, что G' вычисляет G (G' > С), если СД(С') a СВД. Теперь мы можем сказать, что задача экономии памяти в заданной схеме G = (5\ X, L) состоит в нахождении среди схем G' = (S, Χ', I/) любой такой схемы, вычисляющей б?, у которой X' будет иметь наименьшую мощность. Содержательный анализ задачи подсказал нам, что эта задача решается в два этапа: построение графа несовместимости U и его раскраска. В следующем разделе мы займемся обоснованием этой гипотезы. § 2.3. Общая теория Информационный граф. Начнем исследование с описания графа U. Его вершинами являются «связки»— некоторые совокупности информационных связей, (г, а), которые в свою очередь задаются бинарным отношением Μ существования маршрутаг реализующего «передачу информации» от г к а. Сказанное дает нам основание рассмотреть ориентированный граф, вершинами которого являются полюсы Р, а множество дуг задается бинарным отношением М. Этот граф, который мы, не называя его никак специально, уже рисовали во всех наших примерах пунктирными стрелочками, естественно назвать информационным графом 1= (Ρ, Μ). Получив мимоходом его определение, мы, как обычно, займемся его анализом. Начнем с того, что перерисуем информационные графы со всех построенных в главе 1 примеров и соберем их на рис. 2.5. Для наглядности и более четкой с^язи с исходными схемами мы расположим результаты в верхнем ряду, аргументы — в нижнем и пометим полюсы символами операторов, к которым эти полюсы относятся. Простое рассмотрение получившихся графов позволяет сделать несколько наблюдений. Первое. Дуги информационного графа — особого рода. Результат в этих дугах бывает только предшественником, а аргумент — только преемником. По существу, бинарное отношение Μ задано не на прямом произведении РхР, а на прямом произведении RxA, где Л^Л 4ср и ЙП^[ = 0. Графы такого рода называются двудольными. Второе. Знакомство с теоремой 1 из предыдущего раздела убеждает нас в том, что «связки» информационных связей, использованные в главе 1, суть не что иное, как компоненты связности информационного графа. Это наблюдение, в данном контексте почти тривиальное, является для нас сущей находкой. Оно полностью формализует поия-
84 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ тие связки и одновременно показывает, какой важной конструкцией является информационный граф. Третье. Информационный граф в ряде случаев оказывается более глубоким инвариантом, чем носитель. Например, для ШШ ΰι В г Cf Ci С ζ С2 Uf Uz Е1 Е2 Н2 /у Fz Л J2 Hf ί, Jf К Ю α ύ с tf tl due ρ q if нор1'нор1 нор2кор2'призн /мшш И ducj p< t2duczpz qz^ucz4f < прим кор^ tj2 иор12 κορί κορ21 8ы85 ' " " tit πορ2ι κορ22 κορ2ζ дыб^ дь/82 5) ■ Щ I ffS« In ία + abs Ввг 6д, t + - +/ / * шш, ш а Зыд +f < +2 ok Iz If In < +/ "/ t +2 -z +? h */ k *ζ&ώ 5} г) Рис. 2.5. Информационные графы. а) Примеры 5, 6, 7 и 8. б) Пример 9. в) Пример 10. г) Пример 11. операторных схем примеров 5, 6 и 7, 8 мы обнаруживаем, что носители в примерах 5, 6 и 7, 8 разные, а информационный граф — один и тот же. Пытливый ум сразу задаст вопрос о самостоятельной роли информационного графа как инварианта в задаче экономного распределения памяти. Выясняя, этот вопрос, читатель легко может показать, что имеет место
§ 2.3. общая Теория .85 Теорема 2. Пусть 1(G) — информационный граф операторной схемы G. Тогда если G' >> G, то 1(G) является подграфам W). К сожалению, пример рис. 2.4, г) с такой же очевидностью показывает, что обратное утверждение не верно. Совмещение χ ш. у не выбросит ни одной дуги из информационного графа, но полностью исказит картину информационных связей. По-настоящему пытливый ум тем не менее не удовольствуется этим отрицательным общим результатом и будет выяснять, когда же все-таки информационный граф может быть спасен как инвариант. Заметим, что на этом пути исследователь быстро обнаружит, что для линейных операторных схем информационный граф является исчерпывающим инвариантом не только распределения памяти, но и более широкого класса преобразований схемы, связанного с перестановкой операторов. Для более же общего случая он «втравится» в исследование такого класса схем, в которых различные распределения памяти строго сохраняют совокупность информационных связей, не расширяя ее. Мы, однако, сейчас не будем отвлекаться от нашей основной линии общей теории. Уточнение несовместимости. Итак, на основе сделанного небольшого открытия мы можем сформулировать нашу гипотезу так, что вершинами графа несовместимости являются компоненты связности информационного графа операторной схемы. Как таковые, они заслуживают особого термина. Исторически сложилось так, что они называются областями действия (величины). Так как содержательный анализ у нас позади, то смысл этого термина нам ясен: всем полюсам, входящим в область действия, сопоставляется одна и та же величина. Для полного описания графа U нам надо описать бинарное отношение несовместимости между областями действия. Гипотеза для этого у нас уже готова. Дадим сначала чисто словесную формулировку отношения несовместимости. Определение. Две области действия несовместимы, если в каждой из них найдется информационная связь, причем начальный оператор некоторого маршрута одной связи окажется начальным или внутренним оператором некоторого маршрута другой связи. Это определение хотя и требует много воздуха, чтобы произнести его без запинки, все же вполне точно и строго соответствует нашим догадкам, сделанным в 1-й главе. Тем не менее в этом определении есть одна недоговоренность, которая нам была совершенно не видна при рассмотрели содержательных примеров и до которой и сейчас было бы непросто догадаться, если только не бросить еще раз взгляд на рис. 2.1 с различными примерами компонент связности ориентированных графов. На одном из примеров изображены компоненты связности, состоящие из изолиро-
86 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ ванных вершин. Спрашивается, может ли информационный граф иметь изолированные вершины-полюсы. Определение операторной: схемы с очевидностью подсказывает, что это вполне возможно. Изолированный результат — это результат, который нигде н& используется, изолированный аргумент — это аргумент, для которого нет «питающего» его результата. Но тогда возникает вопрос, как для изолированных полюсов определить отношение несовместимости, поскольку при отсутствии дуг информационного графа (информационных связей) говорить о маршрутах нельзя — они отсутствуют тоже. Здесь возникает традиционная дилемма. Надо ли сузить определение операторной схемы, чтобы сохранить определение несовместимости в силе, изгнав из информационного графа изолированные вершины, либо обобщить определение несовместимости на случай произвольного информационного графа. В последнем случае появляется дополнительная задача сделать это обобщение таким образом, чтобы не нарушить наше допущение сопоставления одинаковых величин компонентам связности, оказавшимся совместимыми. Рассмотрим сначала случай изолированного результата г. Вернемся к содержательной трактовке оператора. Когда оператор вырабатывает результат, он «не знает», когда и будет ли вообще его результат использован. Отношение несовместимости возникает из-за того, что при присваивании значения результата неудачно выбранной величине этот результат «убивает» (в американской литературе так и пишут kills) нужное значение (формально — делает невозможным определить тот же маршрут в схеме с перераспределенной памятью). «Этот же» маршрут будет невозможно определить, если конкурирующий результат окажется результатом его внутреннего или начального оператора. Таким образом, оператор V(r) при сопоставлении с информационной связью ведет себя так же, как и начальный оператор маршрута^ конкурирующего в смысле сделанного выше определения. Сопоставим изолированные результаты гиг' друг с другом. Очевидно, что не страшно «убить» неиспользуемый результат, поэтому несовместимость появляется только в том случае, если изолированные результаты оказываются результатами одного и того же оператора V(r) — V(r'). Объявление их совместимыми нарушит правила построения операторной схемы. Рассмотрим теперь изолированный аргумент а. Содержательная интерпретация изолированного аргумента означает, что era значение не влияет на характер выполнения оператора V(a). Какая бы величина ни оказалась сопоставленной аргументу а, V(a) будет выполняться одинаково. Это дает нам возможность считать изолированный аргумент совместимым с любой областью действия в информационном графе.
§ 2.3. 0Б1ЦАЯ ТЕОРИЯ 87 Итак, мы рассмотрели все возможные случаи сочетания компонент связности и знаем, как нам надо модифицировать определение несовместимости. Определение. Две области действия несовместимы тогда и только тогда, когда в каждой из них найдутся соответственно результаты гиг', такие, что либо V(r) = F(r'), либо V(r) оказывается внутренним оператором некоторого маршрута информационной связи (г', а'), либо V(rr) оказывается внутренним оператором некоторого маршрута информационной связи (г, а), где а и а' — некоторые аргументы. Теперь отношение несовместимости И у нас определено для всех областей действия du . . ., dt информационного графа / =■ «= (Р, М). Пусть D = {d1? · . ., dt}. Тогда граф несовместимости U полностью определен как U = (D, Н). Критерий несовместимости. Сделанные определения и их анализ позволяют нам приступить к строгому доказательству основной гипотезы, сложившейся при содержательном рассмотрении задачи, о том, что допустимые распределения памяти — это те, в которых всем полюсам любой пары совместимых областей действия сопоставляется одна и та же величина. Дадим аккуратную формулировку, предварив ей еще одно обозначение. Если в распределении памяти L всем полюсам некоторой области действия d сопоставлена одна и та же величина, то оца будет обозначаться L(d). Теорема. 3. Пусть даны две операторные схемы G = = (5, X, L) и G' — (S, X', U) и dx, . . ., dL — области действия графа 1(G). В этих условиях G' ^> G тогда и только тогда, когда: а) для любой dt (i = 1, . . ., I) L'(p) одно и то же для любого полюса ρ из dt. б) L'(di) Φ L'(dj) для любой пары dt и dj, удовлетворяющих отношению несовместимости в графе U(G). Приступим к доказательству теоремы. Она содержит необходимое и достаточное условие, поэтому нам нужно провести рассуждение в оба конца: от вычисляемости схемой Gr схемы G к уровню и наоборот. Необходимость. Пусть G' )> G. Проверим выполнение условий. Для областей действия, образованных изолированными полюсами,^ условие а) выполняется тривиально. Предположим, что в некоторой области d, содержащей дуги, есть два полюса, ρ и р\ для которых Ь(р)ф£,(р'). Тогда в d обязательно найдется дуга (г, а), для которой также L(r) Φ L(a) (подробное доказательство этой мини-леммы требует некоторого рассуждения, в котором по существу используется свойство связности области d). Но в этом случае пара (г, а) не может быть в Gr информаци-
88 ГЛ. 2. ПОСТАНОВКА ЗАДАЧИ И ОБЩАЯ ТЕОРИЯ онной связью, реализуемой каким бы то ни было маршрутом. А это противоречит условию G )> G. Предположим теперь, что нашлись две несовместимые в графе U(G) области действия dt и dj, для которых тем не менее Z/(dj) = = L'(Dj) = χ. По определению несовместимости мы либо обнаруживаем в таком случае, что в схеме G оказывается оператор с двумя результатами, которым сопоставлена одна и та же величина (это противоречит правилам задания схемы С), либо обнаруживаются два результата, г, г', аргумент а и такой путь V(r) . . . F(r') . . . V(a) (остальные операторы не показаны), который в схеме G оказывается маршрутом т информационной связи г, а: m = ((r,a), F(r) . ./F(r') . . . 7(a)), а в схеме (?', тем не менее, L'(r) = L'(r') — L(a) = χ. Это значитt что т не является маршрутом в схеме С, что опять-таки противоречит условию G' )> G. Необходимость доказана. Достаточность. Пусть теперь выполнены условия теоремы. Предположим, что схема G содержит маршрут т, который отсутствует в схеме G'. Пусть т = ((г, a), V(r) . . . Ft , . . 7(a)), где Ft — произвольный транзитный оператор маршрута т, может быть, отсутствующий. Рассмотрим, по каким причинам этот набор не может быть маршрутом в G. Во-первых, если L'(r) Φ L'(a). Этого, однако, не может быть, потому что как г, так и а принадлежат одной и той же области действия d в схеме G и по условию a) L'(r) = L'(a). Таким образом, если т не содержит транзитных операторов, то он является маршрутом связи (г, а) в схеме G. Во-вторых, если имеется результат г', такой, что V(r') = Ft и L'(rr) = L'(r). Так как Ft — внутренний оператор маршрута т в G, то в G г' принадлежит обязательно некоторой d\ отличной от области действия d, содержащей (г, а). (Это еще одна мини- лемма, требующая проработки определения маршрута и компоненты связности.) В этом случае области действия d и d', по определению, оказываются несовместимыми. Но тогда выполнение условия б) требует, чтобы L'(r') фЬ'{г). Таким образом, ничто при выполнении условий теоремы не мешает тому, чтобы любой т был бы также и маршрутом в G. VV Только что доказанная теорема является основной в нашей общей теории. Она обосновывает весь наш подход к задаче, экономии памяти. Нахождение графа несовместимости. Теперь наше внимание концентрируется на способах задания графа несовместимости. Мы уже разобрались с его вершинами — компонентами связности
§ 2.3. ОБЩАЯ ТЕОРИЯ 89 информационного графа. Мы дали также точное определение несовместимости. Оно в общем случае использует понятие маршрутов, находящихся в специфическом взаимном положении (начало одного является началом или транзитом другого). Мы уже понимаем, что основное направление развития нашей теории — это конструктивизация нашего исходного определения вычисляемости одной схемы другой. Мы не можем контролировать допустимость распределения памяти, изучая непосредственно носитель — множество маршрутов в общем случае бесконечно. Мы уже с помощью теоремы 3 свели контроль за допустимостью распределения памяти к анализу графа несовместимости. Теперь нам нужно сделать •еще один шаг и «изгнать» маршруты как рабочую конструкцию из самого определения несовместимости. Кстати говоря, нам в этом отношении помог анализ изолированных полюсов в информационном графе. Обобщенная формулировка отношения несовместимости, как надеется автор, сделает для читателей естественной формулировку следующей теоремы, которой мы, однако предварим пару обозначений. Пусть d — некоторая область действия в информационном графе схемы G. Тогда обозначим R(d) — множество всех операторов, имеющих своими результатами полюсы из d; T(d) — множество всех операторов, каждый из которых является транзитным хотя бы для одного из маршрутов информационных связей из d. Теорема 4. Две области действия dud' информационного графа схемы G несовместимы тогда и только тогда, когда не пусто множество R(d) n R(d') U R(d) П T(d') U R(d') П T(d). Доказательство этой теоремы крайне просто и является, по существу, перефразировкой определения несовместимости. Если множество не пусто, значит имеется оператор, который вырабатывает результаты, относящиеся к областям действия d и d\ либо, вырабатывая результат одной из областей, является транзитным для маршрута связи другой из областей. Наоборот, выполнение условия несовместимости обеспечивает непустоту указанного множества. VV На этом построение общей теории можно считать законченным. Мы нашли точную постановку задачи, и описали как заданные, так и искомые объекты, нахождение которых в силу доказанных теорем поможет нам в решении задачи. Это — компоненты связности информационного графа, а также множества R(d) и T(d), которые позволят нам строить подлежащий раскраске граф несовместимости.
so ГЛАВА 3 АЛГОРИТМИЗАЦИЯ Содержание этой главы можно рассматривать как углубление общей теории в некотором специфическом направлении. В предыдущей главе мы сосредоточили наше внимание на описании объектов, наличие которых в силу доказанных теорем, позволяет решить задачу экономии памяти. Если для заданной операторной: схемы мы сможем построить информационный граф, то его компоненты связности должны быть взяты в качестве вершин графа несовместимости. Если для каждой компоненты связности d нам: будут известны множество R операторов, результаты которых входят в d, и множество Τ транзитных операторов у маршрутов, обеспечивающих информационные связи из d, то тогда мы можем: полностью определить отношение несовместимости. Наконец, различные варианты раскраски вершин графа несовместимости нам: дадут различные способы распределения памяти; при этом раскраска в минимальное число красок даст наиболее экономное распределение памяти. В этой главе, оставаясь на уровне рассмотрения абстрактных объектов, мы постараемся понять, как все эти объекты могут быть построены: как найти компоненты связности информационного графа, как определить множества R (что просто) и Τ (что существенно сложнее), как, наконец, найти наилучшую раскраску графа несовместимости? Для этих построений нам нужно найти систематические процедуры, которые могут быть положены в основу практического решения задачи экономии памяти, например, на ЭВМ с помощью алгольных программ. Следует напомнить, что содержательный анализ задачи, хотя и на частных примерах, оставил нам немало намеков на то, какими могут быть искомые вычислительные процедуры. § 3.1. Информационный граф Итак, информационный граф / схемы G — это / = (Р, М)г где Ρ — множество полюсов, а М — бинарное отношение между парами (г, а) «иметь информационную связь от результата г к аргументу а». Для того чтобы найти множество D = {dt, . . ., dt] компонент связности, нам достаточно знать, какие полюсы к каким компонептахМ относятся. Из всех этих объектов нам в исход-
§3.1. ИНФОРМАЦИОННЫЙ ГРАФ С1 ной схеме дано только Р. Еще не вникая в суть дела, мы можем высказать одно пожелание, а именно, чтобы в искомой процедуре построения графа / выделение компонент связности происходило €ы по возможности «само собой» по мере обнаружения информационных связей. Еще один намек на подход к разбиению вершин на группы, попадающие в одну компоненту, нам дает доказательство теоремы 1: каждая вершина at графа «искала» соседей, πε- чиная с себя как с изолированной вершины. Затем в процессе построения множеств Dt (из теоремы 1) все связанные вершины вошли в одно и то же множество, а изолированные так и остались изолированными. Транзитивное замыкание. Важный ключ к процедуре нахождения информационного графа нам дала практика построения информационных связей в примерах главы 1: отправляясь от задания величины я, мы двигались вдоль некоторого пути (в линейных схемах — единственного) пока не находили использования х (устанавливая тем самым информационную связь), или пока не встречали новое присваивание величине #, обрывающее наши попытки продолжить маршрут величины, начатый предыдущим присваиванием. Это весьма наглядное напоминание должно быть, однако, сформулировано в более точных терминах, нежели «движение» и «встречи». Здесь нам будет уместно усвоить одно общее Определение. Пусть В — бинарное отношение на -элементах множества А. Транзитивным замыканием Тг (В) называется бинарное отношение В' на этих же элементах, выполняющз- еся для пары (а, а') тогда и только тогда, когда существует конечная последовательность аага2 » . . апаг (η ^ 0) элементов из А, такая, что любая пара соседних элементов в этой последовательности удовлетворяет отношению В. В применении к графам две вершины (а, Ъ) удовлетворяют транзитивному замыканию отношения соседства, если d графе есть путь, ведущий от α к 6. Идею пошагового движения по путям, соединяющим вершины в графе, развивает очевидный алгоритм нахождения транзитивного замыкания. Мы можем быть уверены, что нашли транзитивное замыкание Тг (Г) ориентированного графа (А, Г), если для каждой вершины а е А укажем множество Тг (а) — {х} таких #, для которых пара (а, х) удовлетворяет отношению Тг (Г). Назовем Тг (а) транзитивным образом вершины а. Для этого мы введем для каждой вершины а стартовое множество S и пополняемое множество Г. В начальный нулевой момент положим «S(0)={a} и Г<°> = 0. После этого определим рекуррентный процесс, определяемый следующим соотношением: y(n+i) = fin) м Г(5(п)), S{n*~{) — 7Т('1-Ы)\77(я)#
92v ГЛ. 3. АЛГОРИТМИЗАЦИЯ T(S) обозначает множество преемников вершин из 5. Применение соотношения продолжается до минимального η = iV, такого;, что S<n+1> = 0. В этом случае Г = T(iV>. Поскольку Г<п> не может расширяться неограниченно, очевидно, что такой момент наступит. Остается доказать лемму: Лемма. T = Tv(a). Доказательство. Покажем, что Tr(a) CZ Т. Действительно/ если вершина а' е Тг (а), то в графе существует путь аах . ; . апа!, что можно также выразить отношениями аг е= Г(а), ап е Γ(αη_J, «' е Т(ап). Этот путь всегда можно выбрать так, чтобы а, аг, . , ., ап были бы все разными. Из соотношения для Sw очевидно, что я'еГ(№)), откуда следует, что а! е Г(п+1) а, стало быть, а' е Т. Покажем, что ГсТг (а). Пусть а! е Г. Это значит, что для некоторого η > 0 а' е Г (5(п)). Покажем по индукции, что для любой вершины 6 из 5(п) имеет место включение b e Тг(а). Для η = 1 это очевидно: 5(1) = Γ(α)\{α}. При выполнении условия индукции S^71-1) Q Tr(a), a стало быть, и любой преемник любой вершины из 5(п~1) также будет принадлежать Тг (а). V Мы позволили себе подробно остановиться на этом очень простом доказательстве, которое кажется настолько очевидным, что любая его формализация выглядит неуклюже. Тем не менее этот рекуррентный способ нахождения транзитивных замыканий имеет настолько большое значение в различных алгоритмах на графах, что умение строго доказывать такие и аналогичные соотношения должно даваться читателю без труда. В некоторых случаях, кроме такого рода «свободных» транзитивных замыканий, рассматривают ограниченные транзитивные замыкания, когда при движении по путям появляются «непроходимые» вершины, которые не могут принадлежать путям, соединяющим вершины, связанные транзитивным замыканием такого рода. Если X — множество таких непроходимых вершин, то тогда
§ 3.1. ИНФОРМАЦИОННЫЙ ГРАФ 9S построение, как мы скажем, ограниченного транзитивного образа vTr(a|X) выглядит следующим образом: 5(0) = Г; Г<°> = 0; y(n+i) _ у(п) у γ (5(η>), 5(η+!> = Tinf^\Tin)\X. Нахождение компонент связности. В начале параграфа мы высказали ряд догадок о том, как строить информационный граф и его компоненты связности. В свете сделанных определений η описанных рекуррентных процедур мы можем теперь свести эти догадки вместе следующим образом. Введем понятие «текущей» компоненты связности. Под словом «текущая» мы* понимаем «на какой-то момент построения информационного графа». Пусть дана схема G = (5, X, L). В начальный момент у нас будет столько текущих компонент, сколько полюсовψ так что каждый полюс принадлежит «своей» компоненте. Пусть г — некоторый результат, d(r) — его текущая компонента. Пусть оператор F = F(r), величина χ = L(r) и R(x) — множество операторов схемы, вырабатывающих х. Будем строить для F его ограниченный транзитивный образ Tv(F\R(x)), которое обозначим короче, Е(г). Пусть а\х,..., aik— аргументы операторов из Е(г)г для которых Ь(аг1) = ... = L (aift) = x, a d(a\x), ...,d(aih} — их текущие компоненты. Тогда информационный граф пополняется информационными связями (г, а^),..., (г, aik\ a всем полюсам г, а*1?..., aik сопоставляется общая новая текущая компонента dr =d(r) U й(аг1) U ··· U d(aiky Это построение делается для каждого результата схемы. В итоге мы получим некоторое множество Μ информационных связей и некоторое количество подмножеств полюсов: D = {аг, . . ., dz}. Утверждается, что граф (Р, М) будет информационным графом / схемы G, a D — искомым разбиением ее полюсов по компонентам связности графа. /. Нижеследующее доказательство только что сделанного утверждения читатель может пропустить, но только при условии, что он будет в состоянии самостоятельно провести соответствующее рассуждение. Мы же проведем доказательство хотя бы для того,, чтобы дать возможность менее опытному читателю проконтролировать себя. Сначала опишем процедуру построения более точног так чтобы это описание действительно напоминало алгоритм. Будем использовать стандартные обозначения операторной схемыг введенные в предыдущей главе. Положим в7 начальный момент dx = {πχ}, ..., dr = {nr}r Μ' = 0/ Для каждого i = 1, ..., q рассмотрим результат-rt. Найдегд в заданной схеме следующие объекты и множества; χ = Ь(г^); F = У(гг); R(x) — множество операторов, вырабатывающих х+
94 ГЛ. 3. АЛГОРИТМИЗАЦИЯ Построим по индукции следующие множества: j(n+i) = fin) у Г(5(п>); £(«+0 =Г(п+1)\у(п)\^дм( В процессе построения для каждого а,, такого, что L(a,j) =» = л:, a V(a,j) е= Г(5(п)), образуем d' = d£ |Jdj, и заменяем им как di9 так и dj, и вносим пару (ri? α,·) в Μ'. Условием окончания работы с rt является достижение такого п, что 5(η+1> = 0. Пусть АГ — результирующее множество пар, d\, . . ., d\ — результирующие различные множества среди текущих компонент du . . ., dr. Пусть / = (Ρ, Μ) — информационный граф и Dt = = {Ph Μ ι) — его компонента связности (i = 1, . . ., Ζ). Пока- я;ем, что Af = AT, I = Г и {di, ...,d'z} = {i\, . . ., Рг}. Доказательство разобъем на несколько лемм. а) Α/ {ΞΞ А/'. По определению информационной пары (r^, а7) существует маршрут (ri,aj)Fii...Fik, в котором L (г4) = L (а,·) = χ; Fit = У (r4), Fjfc = У (ау), и ни один из Fi2 ...Fik_i не вырабатывает #. Тогда из определения транзитивного образа Тг (У(г,-)|Д (л·)) вытекает, что оператор Fik&E(ri)9 а стало быть, существуете, для которого Fik^T(Sn). По построению пара (г,·, aj) в таком случае вносится в множество пар. V б) М' cz Af. Рассмотрим пару (гг·, aj), внесенную в ΛΓ. По построению это произошло при некотором значении η при нахождении множеств 2Т(П+1) и Г(5(п>). Другими словами, y(aj) =« = Γ(5(Λ)), при этом L(a7) = L(rt) = χ. По построению 5(п) существует цепочка операторов Fie,..., Fin такая, что Fi0 = У (о)» jFjm εΓ^^ΙΙ^ w^ гс); при этом ни один из Ft не вырабатывает х. Но в таком случае конструкция (rt,aJ)Fu...FinV(aJ) удовлетворяет определению маршрута, откуда следует, что (ги а})е=М. V в) Для каждого dt при фиксированном порядке рассмотрения результатов г1? . . ., rq построение задает некоторую единственную последовательность объединений его элементов в результирующее множество. Докажем интересующие нас свойства множеств d\ индукцией по порядковым номерам этой последовательности. В начальный момент, очевидно, все неравные друг другу текущие компоненты: а) попарно не пересекаются, β) в сумме составляют все множества полюсов,
§3.1. ИНФОРМАЦИОННЫЙ ГРАФ 95 у) каждое множество полностью входит в одно из Pk (к = ι= 1,..-, I). Рассмотрим теперь любой шаг объединения некоторых текущих компонент dt и dj в (dr = dt U dj). Остальные множества при этом остались без изменений. Очевидно, что d' в совокупности с остальными множествами будет по-прежнему удовлетворять свойствам а) и β). Пусть dt с?ии dj cz ΡΌ (1 <: и, ν <Ι Ζ). По построению имеется г^е^ и aj^dj, образующие в схеме информационную пару. В силу транзитивности связности (лемма из теоремы 1, § 2.2), мы сразу получаем, что и^и d7·, а, стало быть, и их объединение dr принадлежат одному и тому же множеству вершин Ри компонент связности Du. V г) Нам осталось показать, что I = V по окончании построения E(rj) для всех результатов схемы. Предоставив читателю догадаться, почему V не может быть меньше Z, предположим, что I < I'. Это значит, что есть хотя бы две различные текущие компоненты d'i и d], каждая из которых содержится в некотором Ри, Из этого факта, а также из свойства а) следует, что в d\ и d] есть по одному полюсу, которые образуют пару (г, а), являющуюся дугой в компоненте связности Ри информационного графа схемы. В силу леммы а) (г, α)εϋί', а это значит, что по построению М' существует некоторое п, при*котором оператор V(a) принадлежит Г(5(п>), пара (г, а) внесена в М\ a d(r) и d(d) объединены в новую текущую компоненту, общую как для г, так и для а> что противоречит допущению о различности d\ и dy V Последние две леммы позволяют заключить, что {<ri,...,tf;} = {/,1,...,/>i}.vv (Контрольный вопрос читателю: почему последнее заключение мы не пишем в форме d\ = P% (i = 1, . . ., Ζ) ?) Для лучшего освоения описанного алгоритма построения информационного графа и выделения его компонент связности мы рекомендуем читателю проверить его работу на примерах хотя бы из первой главы. Для ориентации и подсказки, как разместить данные на бумаге, мы воспроизведем результаты работы алгоритма для примера 11 (алгольная программа с процедурой). На рис. •3.1 перерисована операторная схема, в которой для операторов и полюсов в качестве обозначений взяты просто их порядковые номера. Поскольку как на картинке, так и в таблице в каждой позиции понятно, номером чего является стоящее в позиции число, мы не употребляем буквенных обозначений элементов схемы, за исключением имен величин из памяти. Это поможет читателю более формально проверить работу алгоритма, а кроме того,
S6 ГЛ. 3. АЛГОРИТМИЗАЦИЯ 2* * I «о д < S 2 О о Он оооо ..сч,-. «а CQ о .. .. о ^ •я > ' <и н £ ί ξ 2 X со <ϋ вахээжонм эгааохавхэ аты 1 *-* Ι >α Ι ^ I <« ι *> α. 00 t^ ζ£) Ю ■* °° (Ν Ι "* I S·» s2 Ι ο cd ЕЭ оо ■ h- : to ■ lo : -* ■ 00 —· о CN °£o> } CN t£o> 1 ««—>s ^ΞθΟ | «o^t^i /~~v * lo^o ι 1 о Ю _ : <m сч 1 °* i ·-· G S 01 О ° I ^-v>—ч CN^ CN CN ^ I CO J 1 s—-'·^. CO Ю CO ι CN Θ OS (01 _ 2,00 1 ^^^ о CN^I Ю CO Q σ> σ> CD со -* Ы Q 00 , t^ 00 Ю σ> σ> со Θ G ts~ Oi 1 СГ5 I 7 9 СГ5 1 1 со I Oi I ι a> 1 ι ю I σ> Ι ι 1 1 1 CN 1 СГ5 1 I CM 1 '-*n 1 1 **■ ^
§ 3.1. ИНФОРМАЦИОННЫЙ I 3 1 ε 1 <u 1 я 1 о 1 с 1 s 1 M щке ι >» 1 ^ l· H 1 CM —· О СГ5 00 ϊ^. CO Ю ^ со см _ ·· « 00 h~ СО ю Tf 00 см ·· ^ 12 ι- IS 1СГ5 1*> ,ls" ю |ю 1"* |С0 |СМ 1— : : ι оо 1 ■ * col : ιοί ; тг« ! 00 1 j см| : — 1 : • оо |см i «d- S : со — ■ IcT ■ Ю|>- СМ| — 00 1 -CM h- 1—. 00 |CM 1 ь- 1 Ισ> Ι ю|г» ' (Ν Ι- iiO 00* CM 1^ CM —^ 1Ю CO CM CM Tt-' CM —4 rh CM » CM *** CM* ~|Ю leo | ^1° со |эо icmco CM - ·> 1— rh ~ |OJ CO CM - - 1—"t |CM CO CM - - 1— n< icmco CM ~ - l_ ^ тг |o CO |X> CM CO ^i 1 CM? | I ι "^™"™H 00 ICM I "h 1 ~£3 1 ι*—* 1 <o h I ΙσΓ Ι Ί ъ · 1 || t» I <*ι° Ι ^ 1— I "ΰ I со loo 1 || -a 1 I CM со j n" I ^ 1 —Γ I ϋ 1 <n 1 -a 1 Ico I II Ή 1 1 2s» S» fc, ·**. £> Η Η Λ „. «a ' CQ Η υ <υ 9.Т s о- so £ з ΰ я £ я η 5 о я χ ч оо t^ CO ю n< СО ~ ~ Д^ λ» О CU ИТП 2 СО 3 Ю O-jfi о н н то ca \o о. то α> ο. SOQO a
98 ГЛ. 3. АЛГОРИТМИЗАЦИЯ подготовит- его к «арифметизации» алгоритма, которой мы займемся в главе, иосвященяой реализации. Построение транзитивных образов показано на таблице А· Колонка таблицы соответствует построению Тг(7(г)|Д(Ь(г)))для некоторого результата г. Операторы, воспринимающие L(r), подчеркнуты. Возникающие информационные связи указываются в верхней части соответствующей позиции. В соседних столбцах Рис. 3.1. Пример ч построению информационного графа. а) Операторная схема, б) Информационный граф. показано формирование текущих компонент. В числителе указаны объединяемые результаты, в знаменателе — аргументы. Результирующий информационный граф показан на рис. 3.1, б). Существует одно распределение памяти, которое можно- осуществить без построения графа несовместимости: это сопоставить каждой компоненте связности свою величину. Это, самое неэкономное, распределение памяти называют каноническим. Так оно называется потому, что все возможные распределения памяти могут быть получены из него процедурой, которая аналогична замене переменных: все вхождения в схему одной величины заменяются символом другой величины. Естественно, допустимая экономия имеет место тогда, когда новая величина заменяет несколько величин, которые в каноническом распределении сопоставлены попарно совместимым областям действия.
§ 3.2. ГРАФ НЕСОВМЕСТИМОСТИ 99 § 3.2. Граф несовместимости Вспомним формулировку теоремы 3: две области действия d и dr несовместимы тогда и только тогда, когда R(d)[\R{d')\jR{d)f]T(d')\}R{d')[\T(d) ψ 0, где R(d) — множество операторов, у которых есть результат, принадлежащий d, a T(d) — множество операторов, каждый из которых является транзитным оператором хотя бы одного из маршрутов, реализующих информационную связь, принадлежащую d Множество R(d) строится элементарно: если дано разбиение полюсов по компонентам связности, то из d выбираются все входящие в него результаты rit, . . ., гг , так что R(d) = {V(rit),...,V(rit)\. Прямое замыкание. Для построения T(d) нам нужно «пройтись» вдоль маршрутов информационных связей из d и отметить «проходимые мимо» операторы. Материал предыдущего параграфа побуждает нас при слове «пройтись» вспомнить определение транзитивного замыкания и попробовать применить его в нашем случае. Действительно, если мы будем строить транзитивный образ некоторого оператора V(r), то мы заведомо включим в него все транзитные операторы маршрутов, начинающихся с V(r). Нас, однако, интересуют все результаты компоненты d, поэтому у нас получается естественное определение: Тг(й)=Дтг(7(г,.Л)), из которого мы получаем, что T(d) cz Tr(d). Это, однако, очень слабое включение, так как транзитивный образ содержит в себе все операторы, достижимые от R(d). Вспомнив определение маршрута, мы сразу соображаем, что T(d) можно ограничить более точно, взяв ограниченный транзитивный образ E(rik). Положив E(d)=Tr(R(d)\R(d))=Ujr(V(rik)\R(d))=UiE(rih), (1) получаем, что T(d) cz E(d). Отвлечемся на минуту от основной линии изложения. Предыдущий абзац дает нам еще один пример лаконизма математического языка, требующего от читателя способности различать определяющие и использующие вхождения обозначений рассматрива-
100 ГЛ. 3. АЛГОРИТМИЗАЦИЯ емых объектов. В строке (1) разные члены этого комбинированного равенства имеют разный смысл. У нас есть множество Ε (r/^)t которое по определению равно Tr(V (rtA\R (d)\ РавенствоE(d)= t r= \J E(rt )— это определение нового множества Е (d). Равенство Tr (R (d) | R (d)) = U Tr (V (rlfc) | R (d) ) - это определение ограниченного транзитивного образа некоторого множества (в данном случае R(d)), аналогичное только что сделанному определению обычного транзитивного образа множества вершин. Равенство E(d) = Tv(R(d}\R(d)) — это следствие из сделанных определений, своего рода микротеорема. Заметим, что это чтение не единственное. Можно было бы определить Tr (R(d)\R (d)), затем через него t E(d), а потом вывести заключение, что Ε(d) = (J E(rib). Кроме этого, нам необходим еще один логический шаг. Мы ввели понятие транзитивного образа вершины для того, чтобы формализовать такие свойства, как достижимость одной вершины до другой. Мы получили определение транзитивного образа множества чисто формально как объединение транзитивных образов его элементов. Возникает вопрос, как понятие транзитивного образа множества формализует свойства достижимости. Перечитав еще раз начало параграфа, мы можем сформулировать следующую лемму (для случая свободного транзитивного замыкания): Лемм а. Пусть в некотором графе G Μ = {тг, . . ., тг} — г множество вершин, Tr(M)= (J Tr(mk), a S(M) = {s} — мно- жест во вершин {s}, таких, что для любого s существует такая вершина т е М, что в графе G имеется путь от т до s. Тогда S(M) = Тг (М). Доказательство, a) S (М) cz Тг (М). Предположим противное, т. е. существует вершина s^S(M) и вершина mt, для которых существует путь от mt до s, но s не принадлежит Тг(М). Но в этомслучае s не принадлежит также и Тг (mt), что противоречит свойству Тг (т^). б) Ίν(Μ) cz S(M). Рассмотрим любой элемент ieTr (М). Принадлежа сумме, он тем самым принадлежит одному из слагаемых Тг (т^. Из этого следует, что в графе существует путь от т% к ty что доказывает принадлежность к S(M). v Аналогичное свойство для ограниченного транзитивного замыкания читателю предлагается доказать самостоятельно. Обратное замыкание. Теперь нам нужно посмотреть внимательнее, что же лишнее содержит в себе E(d). При движении по дугам графа переходов мы можем попасть либо в цикл, из которого есть выход, либо в тупиковый цикл, либо упереться в оператор,
Ч 3 2. ГРАФ НЕСОВМЕСТИМОСТИ 101 вырабатывающий ту же величину, либо остановиться у конечного оператора. Нарисуем наугад произвольную операторную схему в упрощенном виде, только с одной областью действия, ллшь бы в ней реа- лизовывались все только что перечисленные логические возможности движения вдоль дуг графа переходов (рис. 3.2, а). Отметим на нем как операторы из Ε (d), так и из Г (d). Продвигаясь по дугам, отправляясь от задающих операторов и откладывая в Ε (d) проходимые операторы, мы прихватываем лишние операторы, потому что не знаем заранее достигнем ли мы на этом пути воспринимающие операторы. Транзитные операторы, в отличие от перечисленных, достижимы не только от задающих операторов, но и от воспринимающих (если двигаться навстречу стрелкам). Высказав с разгона это очевидное наблюдение, нам нелишне будет сделать логическую паузу и осмыслить сказанное. Мы связали движение по дугам графа с построением транзитивного замыкания. Движение против ориентации дуг наводит нас на мысль ввести понятие обратного транзитивного замыкания и определить транзитивный прообраз вершины а, как множеств Тг-^а) таких вершин χ (Тг_1(а) = {я}), для которых пара (х, а) удовлетворяет отношению Тг(Г), где Г, как обычно, множество дуг рассматриваемого графа. Поскольку каждый путь в графе может быть пройден как вдоль дуг, так и навстречу им, введя обозначение Γ-χ(α) как множества предшественников а, сразу получаем аналогичную (предыдущему параграфу) процедуру для нахождения транзитивного прообраза. S^={a}, Г<°> = 0, jp(n+i) __ f{n) у ρ—ι (Sin)), Sin+X) = Tin+i)\T(nK Аналогично определим ограниченный (по отношению к множеству вершин X) транзитивный прообраз Тг-х(а|Х): 5<°>={а}, Г<°> = 0, Г(п-И) — у(л> у ρ—ι (5(п>), 5(п+1) = Т<п+Ц\Т1п*\Х^ В обоих случаях Тг-1 берется как первое Т^п\ равное Г*71-1). Пусть в область действия d входят аргументы а^,..., aJs. Опять-таки рассуждая по аналогии и, вспомнив, что E(d) == = Tv(R(d)\R(d)), приходим к заключению, что T(d) cz Ίν-\Α(ά)\ \R(d)), где A(d) = [V (а^),..., V(a7s)} —множество операторов, воспринимающих величину, сопоставленную области действия d (рис. 3.2, б), а Тг-' (A (d) | R (rf)) = Ц^ Tr-i {V(aH)\ R (d)).
102 ГЛ. 3. АЛГОРИТМИЗАЦИЯ η о о Η ев G* Φ а о и Я· В φ О и ев со
§3 2. ГРАФ НЕСОВМЕСТИМОСТИ 103 Повторив теперь снова нашу мимолетную догадку «транзитные операторы достижимы не только от задающих операторов, но и от воспринимающих», мы сразу можем облечь эту гипотезу в точное утверждение: Τ (d)^E (сОПТг-1^ (d)\R (d)). Читатель, заразившись азартом в поиске решения задачи, может нетерпеливо спросить, почему мы пишем здесь включение, а не равенство. Заметим, что, хотя именно это предположение оказывается ошибочным (пересеките множество Ε (d) из рис. 3.2, а) с множеством Тт-^А^Ща)) из рис. 3.2, б, и вы сразу увидите четыре лишних оператора), тем не менее направленность вопроса весьма плодотворна, и мы поищем, как подправить определение накрывающего множества, которое мы строим с помощью обратного транзитивного замыкания (сразу дадим ему, еще не существующему, обозначение — L (d)), чтобы сохранить подход к на- хождэнию транзитных операторов: Τ (d) = Ε (d)f]L (d). Анализ нашего примера с рис. 3.2 показывает, что ограниченное обратное транзитивное замыкание может содержать в себе задающие операторы, которые, не будучи «проходимыми», являются тем не менее достижимыми. Аналогично, во множестве Ε (d) задающие операторы тоже могут оказаться достижимыми. Из-за эгого задающие операторы могут попасть и в пересечение. Похоже, что концевые (т. е. принадлежащие одному из концов маршрута) задающие операторы являются единственным мусором, проникающим в искомое множество транзитных операторов. Поэтому способ построения множества L (d) надо поправить так, чтобы задающие операторы были бы не только непроходимыми для следующего очередного шага, но и недостижимыми, оставаясь при эгом границей продвижения навстречу дугам. Мы, очевидно, достигнем цели, если будем исключать задающие операторы R (d) не из стартового множества для следующего шага, а на полшага раньше, не допуская их появления в пополнении наращиваемого множества 7Т(П+1). Итак, для каждого аргумента а^ из d: Sm = \v{aJi))> FO) = 0> γ(η+\) = рп) у ρ—ι (S{n^)\R{d), £<»+ι> = т{п+^\Т<пУ> L(aj) = JW, где Ν — наименьшее η, при котором S(n+X) = 0. Для всей же области действия Рис. 3.2, в наглядно показывает, как множества Ε и L, пересекаясь, выделяют множество транзитных операторов.
104 ГЛ. 3. АЛГОРИТМИЗАЦИЯ Желая более тесно связать построение множества L(d) с понятием транзитивного замыкания, мы могли бы назвать его сильно ограниченным транзитивным прообразом, имея в виду, что операторы из ограничивающего множества (в данном случае R(d)) являются не только непроходимыми, но и недостижимыми. Это дополнительное свойство транзитивного замыкания (которое имеет смысл как для прямого, так и для обратного замыканий) можно обозначить двойной чертой, отделяющей ограничивающее множество. Тогда формулировка теоремы, утверждающей способ нахождения транзитных операторов некоторой области действия, будет выглядеть следующим образом: Теорема 5. Пусть d — область действия информационного графа, T(d), A(d) и R(d) — множества транзитных, воспринимающих и задающих операторов соответственно. Тогда T(d) = Тг {R(d)\R{d))r[Tt-\A{d \\R{d)). Доказательство предоставим сделать читателю, наметив только его схему. Обозначим для краткости множество из правой части через EL. Сначала докажем, что EL cz T(d). Берем любой F^EL и, обыгрывая его принадлежность как к прямому, так и к обратному замыканиям, выясняем, что он не вырабатывает величины, сопоставленной области действия d, и достижим как от некоторого вырабатывающего оператора по пути si9 так и от некоторого воспринимающего оператора по встречному пути sj'1 (—1 означает движение навстречу дугам). Затем показываем, что путь sts2 удовлетворяет определению маршрута. Для доказательства T(d) ^ EL перефразируем определение транзитное™ в терминах достижимости как от R (d), так и (навстречу дугам) от A(d). VV Фронтальное построение замыканий. Прежде чем покончить с процедурой построения графа несовместимости, сделаем еще одно замечание, развивающее мысль, которая, вероятно, промелькнула у читателей, которые, не полагаясь полностью на рис. 3.2, сами строили множества Ε (d) и L(d). Заметим, что Ε (d) получается как побочный продукт при построении информационного графа. Имея Ε (rt), построенные для каждого результата гь мы потом объединяем в E(d) те Ε (гг), чьи гг попадали в одну область d. Множество L (d) мы начинаем, однако, строить тогда, когда множества R(d) и A (d) уже найдены (как это показано на примере рис. 3.2). В этом случае становится естественной попытка строить как Ε (d), так и L (d) «фронтально», организуя движение вдоль или навстречу дуг сразу от всех задающих или использующих операторов. Перерисуем управляющий граф с рис. 3.2 на рис. 3.3 в двух экземплярах. На одном экземпляре (3.3, а)) изобразим Τ (d), а на другом (3.3, б)) —- R (d), A (d), а также
§ 3.2. ГРАФ НЕСОВМЕСТИМОСТИ J 05 )N/ I fe £.- И Χ Я И Η Η И φ ο α< ο Η ο Η 4 се Η Η ο θ £ со со о Οι Ж
106 ГЛ. 3. АЛГОРИТМИЗАЦИЯ «слои» операторов, включаемых во множества Ε (d) и L(d) на этапах фронтального построения. Слои нумеруются арабскими цифрами для Ε (d) и римскими — для L(d). Заметим, что число этапов фронтального построения меньше, чем максимальное число этапов при раздельном построении замыканий. Как показывает построение, мы получаем те же Ε (d) и L (d), а, стало быть, и Τ (d). Нам, однако, нужно строго доказать, что фронтальный способ нахождения транзитивных замыканий дает тот же результат, что и раздельное их нахождение с последующим объединением. Уточним сначала термин «фронтальный способ». Он состоит в том, что если мы строим, например, транзитивный образ множества вершин А по отношению к ограничивающему множеству В, то в качестве начального стартового множества берется сразу все множество А, после чего все рекурсивные шаги и критерии окончания применяются так же, как и для одноэлементного стартового множества. В качестве доказательства проведем рассуждение, которое покажет, что построенное фронтальным способом множество удовлетворяет свойствам транзитивного образа как множества достижимых вершин. Лемма. Пусть Тг (А\В) — множество вершин, построенное фронтальным способом. Пусть S(A\B) — множество вершин, таких, что для каждой вершины s^S(A\B) существует вершина а^А, такая, что существует путь от а до s, чьи внутренние вершины не принадлежат В. Тогда Тг (А\В) = S (А\В). Доказательство. S(A\B) с: Ίν(Α\Β). Рассмотрим вершину $^S(A\B). Путь от некоторого aei к s, ανΛ . . . vks (к ^ 0) можно выбрать таким, чтобы все vt были бы различны и ни одна из них не принадлежала бы А. Рассмотрев первые к + 1 этапов построения Тг (А\В), убеждаемся по индукции, что $ попадает в к-е пополняемое множество T^hK Тг(а|5) с= S (А\В). Рассмотрим вершину teTr (A\B). Можно указать номер этапа к, на котором t впервые появился в пополняемом множестве T^h). Для t = £(fe) можно указать вершину ^(Ы)е5(М)5 для· которой г^еГ^ь-1)). Двигаясь аналогично по убывающему к, дойдем в конце концов до стартового множества £<0) = А. Получившаяся цепочка вершин от £(fe) до t^A дает нам путь, удостоверяющий принадлежность t к S(A\B). V Вернувшись к примеру рис. 3.1, мы построим Ε (d) для семи найденных областей действия, объединяя уже полученные Е(г$ для отдельных результатов г^. Множества L (d) построим фронтально, хотя пример и не дает для этого много материала. Процесс и результаты построения показаны на таблице Б. На рис. 3.4, а) для большего удобства перерисован скелет операторной схемы. Еще раз обратите внимание на то, что при построении L(d) начальное стартовое множество *^<°> в пополняемое множество не включается. Однако некото! ые вершины из него могут попасть
§ 8.2. ГРАФ НЕСОВМЕСТИМОСТИ 107 ι II s 4 =6-9; tq I II 44 1 II CO JCJ> 1 CM ΊΙ •(feci i 2, 4J r-oq COCO ЮЮ eoeoco СМ_« — — CM я Η о • t-- CO Ю ^ CO CM *" CO Ll Θ Θ Θ 0 Θ ~ • ~ о 00 со 00 f- ί ю- со со о о N N п< со • ~ см 0 CO Ю Θ • со 0 со еахээжони β 0 0 <° 0 ю ю 0 ю ^ 0 0 0 ^ U0 91чао1(1вхэ 0 • 0 со со 0 0 со \ • 0 0 0 0 0 0 г» Θ Θ со со CN* CM ~ ю ю 0 0 см яолгга . CO СМ П< (N со Tf edawoH ~ ~ ю со 0 1 0 0 -со со - i"5 *<0 **-1 1 1 см <м S ^ о со о S S 3 о К S <L> О Η о о с: g ^ о.
108 ГЛ. 3. АЛГОРИТМИЗАЦИЯ в L(d) на более поздних этапах (см. столбец 2 в построении L(d)). Это не удивительно: мы уже замечали, что конечный оператор одного маршрута может быть транзитным оператором другого маршрута из той же области действия. Как уже указывалось, по построенным областям действия аъ . . ., dl9 множествам Ε (di) и Ь(аг) множество транзитных операторов находится немедленно: Τ(dt) = Ε (di)p\L(di) (i = 1, ... ..., Ζ), множество начальных операторов Rjldi) непосредственно извлекается из скелета операторной схемы. После этого нахождение отношения несовместимости между областями действия делается очень просто. Расположив «параллельно» множества R н Т, мы для каждого i = 1, ..., I , Щ)... Щ) /^T(dj)... Щ)х производим сравнение на предмет наличия общих элементов между тремя парами множеств (как показано на схеме) R(dt) и R(dj)9 R(di) и T(dj), а также Т(аь) и R(dj) по очереди для всех / > i. Результат сравнения (пусто — не пусто) заносим в матрицу порядка 1x1. В результате этой процедуры в матрице окажется заполненным верхний треугольник (часть матрицы, расположенная над главной диагональю). Так как отношение несовместимости симметрично, нижний треугольник заполняется симметрично верхнему относительно главной диагонали. На таблице в качестве символа «не пусто» для контроля указаны элементы непустого множества R(dt) f] R(dj) [j R(dt) Π T(dj) [J T(dt) Π R(dj). Обозначив элементы построенной матрицы Ηί}·, обнаруживаем, что она нам в точности задает отношение несовместимости для графа несовместимости U = (Ζ), Н), где (напоминаем) D = {йг, . . ., dt}: dt и dj несовместимы, т. е. смежны в графе U тогда и только тогда, когда Hij не пусто. Результирующий граф несовместимости тоже изображен на рис. 3.4, б). Естественно, что он совпадает с точностью до обозначений с графом, нарисованным на рис. 1.11. Мимолетная ссылка на материал первой главы дает нам повод перевести дыхание после сугубо делового тона текущей главы и оценить степень нашего прогресса. Наша задача экономии памяти, какой бы скромной она ни казалась, отражает тем не менее многие типичные стороны любого математического исследования. В частности, на материале наших первых трех глав мы можем обратить внимание читателя на различие познавательной и прикладной, или, точнее, конструктивной, частей нашего исследования. В первых двух главах преобладал познавательный процесс: мы выделяли сущности в задаче экономии памяти и находили для них наиболее подходящие математические абстракции. Работа гке в третьей главе приобрела существенно иной характер. Она
§ 3.2. ГРАФ НЕСОВМЕСТИМОСТИ 109 в какой-то степени утратила свой специфический характер: мы все меньше говорим об экономии памяти, даже если и продолжаем говорить об операторах, величинах, аргументах и результатах. Мы говорили о транзитивных замыканиях и будем говорить о раскраске вершин графа. Задача утратила свою цельность, рассыпалась на кусочки процессов, каждый из которых лучше выразим Ю ' δ) Рис. 3.4. Пример к построению графа несовместимости. а) Скелет схемы. Полюса помечены номерами областей действия, б) Граф песо вместимости. в каких-то других более общих терминах. Для некоторых читателей этот технический материал, может быть, покажется более скучным и интерес ослабеет. Вот тут-то и самое время сказать, что эта промежуточная часть и есть самый «вкусный хлеб» профессионального математика: теоретик всегда будет искать в конкретной задаче зерна абстрактных построений и общих теорий, которые будут интересовать его гораздо больше, нежели исходный материал; для конструктивиста-прикладника всегда будет наслаждением «поверить алгеброй гармонию» и, лишив задачу всякой специфичности, расчленить ее на последовательность простых, элегантных в своей четкости и прозрачности процедур. Таковыми, без сомнения, являются эффективные и очень регулярные процедуры построения транзитивных замыканий, к которым мы свели
110 ГЛ. 3. АЛГОРИТМИЗАЦИЯ наши подзадачи нахождения компонент связности информационного графа и построения отношения несовместимости. Если же мы по-прежнему считаем себя лишь адвокатами нашей конкретной задачи, то мы имеем право с определенным удовлетворением заметить, что хотя мы и не так много добавили к нашему знанию, добытому в первых главах, мы обогатили себя силой всеобщности разработанных нами процедур, приближающих нас к конечной цели: передать машине наше знание в эффективной, т. е.*доступной для реального употребления форме. § 3.3. Раскраска вершин графа. Общее исследование Дадим формальное определение задачи нахождения минимальной раскраски. Раскраской вершин неориентированного графа G ==· (X, Я) называется любое отображение С : X -> К множества вершин X = {хх, . . ., хп} на произвольное конечное множество К = {кг, . . ., кт) (т <! п). Элементы множества К называются красками. Раскраска называется правильной, если для любых i и 7 выполняется условие {xt, xj)^R=^k(Xi) =^= k(xj). (Выражение А =>· В является сокращенной записью стандартной фразы: из того, что выполняется А, следует, что выполняется В.) Минимальной раскраской называется любая такая правильная раскраска, в которой число красок меньше или равно числу красок в любой другой правильной раскраске данного графа. Очевидно, что число красок, используемых в любой минимальной раскраске, одно и то же: оно характеризует сам граф, и обозначается %(G) или просто X, когда ясно, о каком графе идет речь, и называется хроматическим числом графа G. Если нужно указать число красок, использованных при какой-то любой раскраске С графа G, то его обозначают h(G, С). Анализ тривиального решения. Из определения непосредственно вытекает, что для доказательства минимальности некоторой раскраски С нужно уметь показывать, что не существует правильной раскраски в меньшее число цветов, нежели h(G, С). Не менее очевидно, что поскольку число различных раскрасок графа конечно, задача нахождения минимальной раскраски и хроматического числа в некотором смысле тривиальна: надо взять все раскраски, выбрать из них правильные и из правильных выбрать раскраску с наименьшим числом цветов. В этот момент будет уместно оценить масштабы такого перебора. Пусть граф из η вершин можно раскрасить Z(ri) разными способами. Если мы рассмотрим граф, содержащий на одну вершину больше, то при любой раскраске первых η вершин мы можем новую вершину окрасить либо любой из η использованных красок,
§ 3.3. РАСКРАСКА ВЕРШИН ГРАФА. ОБЩЕЕ ИССЛЕДОВАНИЕ Щ либо использовать (п + 1)-ю краску. Таким образом, при переходе от графа с η вершинами к графу с η + 1 вершиной каждая раскраска тг-вершшшого графа порождает η + 1 раскраску {п + 1)-вершинного, т. е. Ζ(η + 1) = Ζ(η)Χ(η + 1). Если- сообразить, что Z(l) = 1, то сразу обнаруживаем, что Ζ(η) = п\. Автор был бы счастлив, если в этом месте критически настроенный читатель прервал его изложение, задав хотя бы один из трех вопросов по поводу этого подсчета: 1. Как учитываются такие раскраски (п + 1)-вершинных графов, в которых (п + 1)-я краска используется более одного раза? 2. Соотношение Ζ(η + 1) = Ζ(η)Χ(η + ί) справедливо только в том случае, если разные раскраски тг-вершинных графов будут приводить по сделанному построению тоже к разным раскраскам. Так ли это? И, вообще, 3. Что такое разные раскраски? Эти вопросы тем более уместны, что можно было бы существенно проще получить еще один подсчет числа раскрасок: имеем и-вершинный граф и η красок. Каждую вершину можно раскрасить любой из η красок, т. е. η способами. Все раскраски получим, сочетая все комбинации каждой раскраски для каждой вершины. Общее число Υ(η) комбинаций равно η Χ η Χ ... Χ η = ηη. η раз Сопоставим эти два способа подсчета для η = 3. Для случая оценки Ζ (η) способ получения раскрасок автоматически следует из индуктивного соотношения между Ζ(η) и Ζ(η + 1). Способ получения раскрасок для оценки Υ(η) становится ясным, если рассмотреть любую раскраску как запись тг-значного числа в п- ричной системе, где роль разрядов играют вершины графа, а цифр — краски. В результате мы получим следующие раскраски (вершины будем различать символами а, Ъ и с, а в качестве красок возьмем числа 1, 2 и 3). Z(n): Z(3)=6 п=1: а и=2: с Ъ и=3: а Ъ с 1 11 111 12 12 1 1 1 2 1 2 2 1 1 3 12 3 Г(п) а Ь 1 1 1 1 1 1 1 2 1 2 1 2 1 3 1 3 1 3 2 1 2 1 2 1 2 2 2 2 2 2 с 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 У(3) =27 а Ъ с 2 3 1 2 3 2 2 3 3 3 1 1 3 1 2 3 1 3 3 2 1 3 2 2 3 2 3 3 3 1 3 3 2 3 3 3
112 ГЛ. 3. АЛГОРИТМИЗАЦИЯ Сравнивая раскраски, мы обнаруживаем, что метод У дает нам много «избыточных» раскрасок. Нас не интересуют все раскраски сами по себе; что нам важно — это иметь возможность среди всех правильных выбрать минимальную. Если мы можем раскрасить граф одной краской, нам не важно, будет ли это краска 1 или краска 2. С этой точки зрения мы усматриваем, что хотя метод Ζ дает формально не все раскраски, он содержит тем не менее все «интересные» раскраски, т. е. такие, из которых любая раскраска может быть получена тривиальным перекрашиванием, т. е. когда одна какая-то краска заменяется другой, не присутствующей в исходной раскраске. Сопоставим каждой раскраске из Ζ(3) те раскраски из У(3), которые могут быть получены последовательностью таких перекрашиваний: 111-^111 222 333 112-^112 223 331 113->113 221 332 121 -►121 131 212 232 313 323 122 -►122 133 211 233 311 322 123 -> 123 132 213 231 312 3£1 Обозначим множества раскрасок, получаемых по методу Ζ и методу Y, Cz,n и Су,п соответственно. Докажем, что для любой раскраски c^CY,n существует раскраска c'gCz,tu которая может быть получена из с путем некоторого тривиального перекрашивания. Пусть с = к19 к2у . . ., кп. Пусть il9 i2,. . ., it (t ^ ή) — краски, перечисленные в порядке их использования в раскраске. Рассмотрим раскраску С = /cj, ηΝ>» · · ·» &п» полученную путем замены каждого ц на / (Z= 1, . . ., £). В такой раскраске для любого / = 2, . . ., η краска к\ либо совпадает с одной из красок, красящих вершины к\, . . ., к)-19 либо имеет номер, на единицу больший, нежели максимальный из номеров этих красок. Отсюда следует, что с'еС2)П. Итак, лемма доказан». V Вспомнив формулу Стирлинга для п\ п\ жппе~п]/2пп> мы видим, что метод Ζ примерно в еп раз экономнее «тупого» пере-
§ 3 3. РАСКРАСКА ВЕРШИН ГРАФА.ОБЩЕЕ ИССЛЕДОВАНИЕ ИЗ бора раскрасок по методу Y. Однако даже он создает раскраски с некоторым «запасом»: из 6 раскрасок только 5 «по-настоящему различных» (читателя приглашаем подумать, что это в точности значит), а раскраски 112 и 113 сводятся одна к другой с помощью перекраски. Другой источник «запаса» состоит в том, что мы порождаем не только правильные раскраски, которые, собственно, нас и интересуют, но и любые. Подсчет числа правильных раскрасок уже гораздо сложнее. Во-первых, число раскрасок уже не является функцией только числа вершин, а существенно зависит от графа: метода даст для графа с η изолированными вершинами все п\ раскрасок (каждая из которых является правильной), а для полного тг-графа (п вершин, попарно смежных) только одну правильную раскраску 1, 2, ..., п. Во-вторых, оценка оказывается не точной, а асимптотической (как формула Стирлинга), т. е. стремящейся к точной при п—>-оо. В нашем изложении нет возможности доказывать эту оценку, мы только скажем, что асимптотически число правильных раскрасок связных графов с η вершинами оценивается функцией еп. Этот небольшой экскурс в комбинаторику, каким бы поверхностным он ни был, достаточен для нас в одном: любая попытка поиска минимальной раскраски прямым перебором всех возможностей обречена на провал, если нас интересует эффективное решение задачи экономии памяти. Необходимость общего рассмотрения. Прежде чем развивать менее тривиальный подход к поиску минимальных раскрасок, нам надо понять: а нужно ли рассматривать проблему в полной всеобщности. При всей увлеченности очередной интересной математической задачей надо помнить, что в контексте нашего исследования раскраска вершин графа нам нужна не сама по себе, а как средство экономного распределения памяти. Может быть, графы несовместимости, получающиеся для операторных схем, обладают какими-нибудь специальными свойствами, которые могли бы облегчить поиск минимальной раскраски. Например, известно, что любой плоский граф можно раскрасить не более чем пятью красками. Вопросы подобного рода нужно задавать себе каждый раз после сведения интересующей нас специальной задачи (экономия памяти) к общей проблеме (раскраска вершин графа). К сожалению, в нашем случае мы очень быстро приходим к отрицательному ответу на поставленный вопрос. Мы покажем, что для любого неориентированного графа Г(У, W) можно построить операторную схему, для которой ее граф несовместимости будет графом T(Y, W). Попробуем вывести конструкцию непосредственно из условия задачи. Пусть Υ = {уъ . . ., yt}. Рассмотрим некоторое ребро графа (уи y/)^W. По условию задачи оно должно изображать несовместимость двух областей действия yt и у}. Отношение несовместимости требует непустоты множества
414 ГЛ. 3. АЛГОРИТМИЗАЦИЯ Я(Уг) П ВД U T(yj) П R(yt) U ЩУг) П Г(ю). Придумать фрагмент операторной схемы, который обеспечивал бы непустоту такого множества, нетрудно. Важно, однако, сделать это как можно проще, единообразно, а главное, так, чтобы в результирующей операторной схеме построенные фрагменты не мешали бы друг другу и не создали бы какие-то производные неконтролируемые яесовместимости, не предусмотренные в исходном графе Т. По принципу экономии мышления естественнее всего создать несовместимость, введя в схему оператор fij с двумя результатами, одному из которых сопоставляется величина xt, а другому х;- (тем самым у нас сразу появляется память X = х1у . . ., хх — по одной величине х% на каждую требуемую область действия yt). Заметим, что при таком построении в схеме для каждой области действия yt окажется столько операторов fij, со сколькими другими вершинами yj смежна вершина уи или, выражаясь языком теории графов, скольким ребрам инцидентна вершина у χ. Если у% — изолированная вершина графа Т, для нее нужно все равно завести область действия, но не связанную ни с какой другой. Для этого достаточно заиметь оператор fi с одним результатом #г·. От каждого оператора fij должны вести дуги, приводящие в конце концов на какие-то операторы, воспринимающие xt и xj. При этом важно, чтобы все результаты, которым сопоставлен хи попали бы в одну компоненту связности информационного графа. Опять-таки этого проще всего добиться, заведя для каждой уг по одному оператору gi с одним аргументом, которому сопоставляется величина xt. Поскольку, как нам кажется, введя операторы fij, мы уже ζ~τ Ρΰδρα графа Τ Иьолиробаниые дершины графа Ύ _2_ L^Lj ·· . \ ?■?/ • 1 Si | ·· \дъ ■ ГЛ ·· О/ • \ Ά \· ,_£_, • ПО Рис. 3.5. Любой неориентированный граф Τ может быть графом несовместимости. обеспечили несовместимость, у нас нет необходимости вводить в схему транзитные операторы, а сразу провести дуги от оператора fij к операторам gi и gj. В результате у нас получается конфигурация, изображенная на рис. 3.5. Формально, это уже вполне правильная операторная схема, хотя и не имеющая привычных —
§3 3. РАСКРАСКА ВЕРШИН ГРАФА.ОБЩЕЕ ИССЛЕДОВАНИЕ Ц5 одного входного и одного выходного — операторов. Правда,, пристроить их ничего не стоит, что и показано на примере, конкретизирующем наше построение на рис. 3.6. Строго говоряг наше построение требует обратного рассуждения, доказывающего* его правильность, однако автор надеется, что читатель сможет это сделать самостоятельно. Ю Рис. 3.6. Пример построения операторной схемы по заданному графу несовместимости. а) Граф. б) Схема. Оценки сложности алгоритмов. Снова столкнувшись с необходимостью рассматривать задачу раскраски вершин графа в ее полной всеобщности в поисках более эффективного алгоритма нахождения минимальной раскраски, мы должны установить себе определенные рамки этого поиска. Поясним, что мы имеем в виду. Мы установили, что для решения задачи «в лоб» нам нужно построить η раскрасок и на каждую раскраску потратить еще какое-то количество операций, чтобы определить ее правильность и подсчитать число использованных красок. Это количество., операций будет заведомо не более высокого порядка, чем /г2. Таким образом, общее количество «элементарных» операций при полном переборе будет порядка п2п\, если считать элементарной операцией простую манипуляцию с одной вершиной или одним ребром графа *). (Заметим, что множитель пг перед п\ почти ничего не значит по сравнению с п\, так как п\ Χ η Χ η < (η + 2)!: можно сказать, что этот множитель равносилен построению раскрасок для графа, содержащего на две вершины больше, чем исходный.) *) Ниже мы поговорим об «элементарных» операциях более подробно.
116 ГЛ. 3. АЛГОРИТМИЗАЦИЯ Если мы будем более осмотрительно строить раскраски, ограничиваясь только правильными, то тогда согласно приведенной оценке, мы должны будем потратить порядка п2еп операций, взяв п2 как завышенную оценку числа действий для получения правильной раскраски. Так вот, когда мы говорим о рамках поиска эффективного решения комбинаторной задачи, мы имеем в виду две границы. Одна граница — это то, что называют нижней оценкой сложности алгоритма. Под этим имеют в виду математически доказуемое утверждение о том, что данная задача в принципе не может быть решена менее, чем в некоторое, указываемое этой нижней оценкой, число элементарных операций. Получение достоверных нижних оценок конкретных алгоритмов это, как правило, трудные математические задачи, хотя в основе их решения часто лежат весьма простые, но фундаментальные наблюдения. Например, очень легко показать, что в общем случае невозможно вычислить функцию η переменных менее чем за η — 1 шагов, если на каждом шаге выполнять бинарную операцию, т. е. вычисляющую функцию двух переменных. Для простоты рассмотрим случай η = 2fe. В качестве аксиомы возьмем очевидное утверждение, что если функция существенно зависит от каждой из η переменных (т. е. изменение каждой из них может изменить значение функции), то в запись алгоритма каждая из переменных должна войти хотя бы по разу; при этом должна существовать хотя бы косвенная информационная связь от этого вхождения к результату функции (понятие косвенной информационной связи иллюстрдруется рис. 3.7, <?)). Итак, за один шаг мы можем вычислить одну операцию, реализующую функцию двух переменных. За два шага, т. е. выполняя две операции, мы можем реализовать, как показано, функцию не более чем трех переменных (если же мы подставим в четыре возможных аргумента двух операций четыре независимые переменные, то мы не сможем связать друг с другом эти операции: рис. 3.7, б)). Выполняя три шага, мы можем реализовать функцию четырех переменных, при этом двумя способами, как показано на рис. 3.7, в). Мы выберем вариант симметричного каскада, так как он сразу'подсказывает общее построение ^-ярусного дерева информационных связей, обеспечивающего вычисление функции 2k переменных не менее, чем за 1 -f 2 -f- . . . -f 2fe~2 + 2A ""1== = 2k — 1 шагов (рис. 3.7, г)). Уже этот почти тривиальный результат дает нам некоторый намек на возможный источник высокой сложности алгоритма поиска минимальной раскраски: если у нас нет другой возможности выявить минимальную раскраску графа из η вершин, как сравнив ее с еп другими раскрасками, нам для этого придется выполнить не менее еп операций, даже если считать сравнение двух раскрасок за одну операцию.
§ 3.3. РАСКРАСКА ВЕРШИН ГРАФА. ОБЩЕЕ ИССЛЕДОВАНИЕ Ш Итак, мы пришли к печальному итогу, что точное решение задачи о минимальной раскраске вершин графа не может быть получено иначе как «полным перебором», т. е. за число шагов, сравнимое с общим количеством всех возможных правильных раскрасок. Термин «полный перебор» используется в связи с тем, что для данной задачи, как и для многих других комбинаторных задач, ее формулировка может быть сведена к следующей общей Xf Хр Х$ Xfy ϋϋ Т^^" X/ X2 'Х$ ^U Д-2. Xf Х2 α) δ) 6) Z5 Xif \_ΛΙКосденная ty Ρ/ сбязь Φ ^ 111 Ι 2ΪΗоперации (п=2киргументо8) 4 операции {8 аргументов) 2 операции (4аргумента) 1 операция (2 аргумента) г) Рис. 3.7. Каскадная реализация функции 2& переменных. а) Одна операция, б) Две операции, в) Три операции, г) Общая конструкция. проблеме: дано некоторое конечное множество (в данном случае множество всех раскрасок), найти в нем некоторый элемент с заданным свойством (в данном случае минимальную раскраску). Задача решается полным перебором, если для нахождения требуемого элемента надо затратить число шагов, сравнимое с мощностью множества. Задача о сечениях. Не надо думать, что все комбинаторные задачи обладают таким неприятным свойством, как требовать полного перебора. У автора в запасе есть хорошая задача, имеющая.
118 ГЛ. 3. АЛГОРИТМИЗАЦИЯ кстати, прямое отношение к общей проблеме, обсуждаемой в пер· вой части книги. Вернемся к обсуждению примеров 6 и 7 главы 1, в которых вычислялось #59. Обе программы вычисляли я09 по формуле *» = (((* Х^Х ((я2)2)2 Χ (((ζ2)2)2)2) Χ ((((*2)2)2)2)2), однако порядок вычислений был различным. Различие порядка вычислений существенно влияло на объем требуемой памяти,, который, как мы выяснили, для линейных программ равен максимальной ширине сечения информационных связей. Освежим в памяти вид сечений в каждой из программ (рис. 3.8), а заодно 0% Ер г ?*, Ι Ι qX Π*] Ι Ι I q3! JJJjgD 1 1 1 Sa-fif 4$ δ) x9 \ i в) Рис. 3.8. Линейная программа как упорядочение дерева формулы // = я59. а) Дерево формулы, б) Неэкономное упорядочение, в) Минимальное упорядочение. изобразим информационные связи в самой формуле, получив каскадную конструкцию, аналогичную рис. 3.7, г) (для простоты будем считать вычисление 8-й, 16-й и 32-й степеней элементарными операциями). Назовем конструкцию, изображающую формулу, каскадным информационным графом. Он отличается от обычного информационного графа тем, что на нем, кроме полюсов и информационных связей, изображены операторы и указано соответствие полюсов операторам (отображение V в определении/операторной схемы). Будем рассматривать операторы как вершины каскадного информационного графа. Тогда этот ориентированный граф άά- а)
§ 3.3. РАСКРАСКА ВЕРШИН ГРАФА. ОБЩЕЕ ИССЛЕДОВАНИЕ Ц9 ляется графом особого вида, называемого деревом. Он имеет одну вершину, не имеющую исходящей дуги и называемую корнем дерева. Он имеет также серию висячих вершин, не имеющих входящих дуг. Все вершины, кроме корня, имеют но одной исходящей дуге. Наконец, для каждой висячей вершины есть один и только один путь к корню. Эти три свойства полностью характеризуют графы, являющиеся деревом *). Взяв вместе с каждой вершиной ν дерева ее обратное транзитивное замыкание, получим подграф Τ (ν), который тоже является деревом с корнем v. Информационные связи между вершинами дерева формулы задают частичное отношение порядка выполнения операций при вычислении формулы: любая вершина ν должна выполняться после любой вершины из Τ (ν). Это отношение порядка частично в том смысле, что оно предписывает порядок выполнения не полностью: вершины, лежащие на пути, соединяющем висячую вершину с корнем, должны выполняться друг по отношению к другу строго в том порядке, в каком они проходятся в этом пути; с другой стороны, для двух вершин νχ и у2, вычисляющих аргументы какой- либо бинарной операции w, любая пара вершин из деревьев T{v^) и Τ(ν2) соответственно может друг по отношению к другу выполняться в любом порядке. Эта частичность упорядоченности вершин в дереве формулы и является источником того, что одна и та же формула может быть запрограммирована многими разными способами (два способа программирования формулы для вычисления х59 и показаны на рис. 3.8, б) и в)). Любая программа, вычисляющая формулу, задает полный порядок выполнения операций, образующих формулу. При этом, однако, сохраняется частичный порядок, установленный информационными связями в формуле. Итак, программой выполнения формулы может быть любое полное упорядочение операций формулы, сохраняющее присущий ей частичный порядок. Мы видим, что различные варианты программ, вычисляющие формулу, требуют разного количества ячеек памяти, вычисляемого как максимальная ширина сечений информационных связей. В связи с этим естественно возникает комбинаторная задача: найти такое упорядочение вершин дерева формулы, которое имеет наименьшую ширину среди всех упорядочений (при этом, говоря о ширине упорядочения, мы имеем в виду максимальную ширину среди всех сечений при заданном упорядочении). Эта задача — типичный пример так называемых «минимаксных» комбинаторных проблем, часто встречающихся в математике. Найденное таким *) Дерево может быть определено и с противоположной ориентацией дуг по отношению к корню и висячим вершинам. Последние называют также концевыми или терминальными вершинами или просто терминалами.
120 ГЛ. 3. АЛГОРИТМИЗАЦИЯ образом сечение мы тоже будем называть минимаксным сечением формулы. Сначала оценим общее количество вариантов упорядочения вершин дерева. Для простоты возьмем случай симметричного или, как говорят, равновесного к-яруспото бинарного дерева (рис. 3.7, г)), имеющего 2к аргументов, 2к — 1 вершин, из них 2к~1 висячих. Будем подсчитывать число упорядочений индукцией по числу ярусов. Рассмотрим некоторую невисячую вершину дерева w, и ее предшественников иг и z;2. Мы уже заметили, что каждая пара вершин из Т(иг) и T(v2) соответственно может быть произвольно упорядочена при условии, что обе они будут предшествовать w. Пусть тп — число вершин в деревьях Τ{υ^) и Τ(υ2) (в силу симметрии они одинаковы). Пусть А и В — какие-то упорядочения вершин из T(vi) и T(v2) соответственно. Тогда при заданных А и В мы можем получить серию упорядочений для дерева T\w) таким образом: перемешаем каким-то произвольным образом вершины из Т(их) и вершины из T(v2), но так, чтобы относительные порядки А и В между вершинами, относящимися к одному дереву, сохранились бы (назовем эту процедуру упорядоченным смешиванием последовательностей Л и β) и вслед за этим упорядочением длины 2пг поместим вершину w. Пусть Щр, q) — количество всех возможных упорядоченных смешиваний двух последовательностей длин ρ и q соответственно, а М — число всевозможных упорядочений вершин деревьев как T(v^), так и Τ(υ2). Тогда число М' всевозможных упорядочений вершин дерева T(w) будет равно М' = М2.Д(т, m). (1) Оценим теперь функцию R(p, q). Будем для краткости последовательность длины η называть и-набором. Решение задачи упорядоченного смешивания g-набора с р-набором можно понимать так, что из некоторых заданных ρ -\-q «мест», какие-то ρ мегт занимаются р-набором, а оставшиеся q мест занимаются g-набором. Очевидно, что любое упорядоченное смешивание характеризуется выбором некоторых ρ мест из заданных ρ -\- q мест и, наоборот любой вьпэор ρ мест однозначно задает некоторое упорядоченное смешивание. Отсюда сразу получаем, что Д(р,д) = С2+, = ^! (2) Пусть Mh·— число всевозможных упорядочений к -ярусного равновесного бинарного дерева. Тогда (1) и (2) вместе дают соотношение
§ 3.3. РАСКРАСКА ВЕРШИН ГРАФА. ОБЩЕЕ ИССЛЕДОВАНИЕ 121 Назовем числитель и знаменатель дроби соответственно повышающим и понижающим факториалами. Само соотношение обозначим F(k — 1) и назовем к — 1 его порядком. Подставим в Mh—X его выражение через Mfe_2, т. е. применим соотношение F(k — 2): м -м" U*-1-^!» (2*-2У· _ к~ h~2 [(2fe-2-l)!]4 ' [(2^-1-l)!]2 ■Μ" [(2*-ΐ-2)!]« (2ft-2)! *~2 t(2fc-i _ 2)! (2*-1 - 1)J2 f(2*-2- 1)Й4 "a-2 (2*-2)! (2*-2-!)1 [(2Λ-2_ι)!]4' Мы видим закономерность в применении соотношения /\& — 2), состоящую в том, что повышающий факториал соотношения F(k — 2) сокращается с понижающим факториалом соотношения F(k— 1), оставляя в знаменателе степенной множитель с показателем, равным двойке в степени, дополняющей порядок применяемого соотношения до к — 1. При последовательном применении соотношений F(k — i) (i = 1, . . ., к — 1) в выражении для Mh в числителе будет получаться Af2\_j и сохраняться факториаль- ный множитель (2к — 2)!, а в знаменателе — накапливаться степенные множители и получаться понижающий факториал l(2fe—i — 1)! Р. После применения соотношения F(i) получим, что Mh= "Г* (2*-2). (2*-1- 1)а1х ... х(Щ-1)*л * [(21 —I)!]2* 1# Поскольку Л/\ = 1, то окончательное выражение получает вид; м (2*-2)1 Мк — "ГГЦ Π (2*-»)' Я\2 ft—г i=l Упростим полученное выражение, заменив правую часть ее нижней оценкой, увеличив знаменатель за счет замены 2i — 1 на 2*: f£_2)! _ (2*-2)! (2*-2)! Ш h <>> ь— 1 ft—i t . ft—1 /ft—1 ι ' TT 2i2k Σ г2*~г 2* Σ i2—Ч "i 2i=1 2 ^ 1 Слагаемые в скобках — это отрезок сходящегося числового ряда с суммой, согласно задачнику Б. П. Демидовича, равной двум. Заменив отрезок ряда его суммой, мы усилим неравенство,
122 ГЛ. 3. АЛГОРИТМИЗАЦИЯ и вспомнив, что 2k — 1 = η, где η — число операций в дереве, получим окончательную оценку для Mk: Итак, мы обнаружили, что число различных вариантов упорядочивания операций формулы, представляемой равновесным деревом с η вершинами, растет с η несколько медленнее, чемтг! В то же время мы сейчас покажем, что для некоторого (правда, упрощенного) способа вычисления формул их минимаксное сечение может быть найдено очень простым алгоритмом с числом действий порядка всего лишь п. Упрощение будет состоять в том, что аргументы формулы'не входят в категорию величин, для которых мы хотим экономно распределить память, и что, если в формуле есть совпадающие подвыражения, то они программируются каждый раз заново. В этом случае информационные связи в формуле будут действительно образовывать дерево, а не какой-либо более сложный граф (однако мы не требуем, чтобы дерево было строго бинарным и равновесным, в частности, оно может содержать унарные операции, т. е. над одним аргументом). Опишем этот алгоритм индукцией по построению дерева. Другими словами, говоря о дереве T(w) с корнем w, мы будем рассматривать два случая: а) w имеет единственного предшественника ν, являющегося корнем дерева Τ (ν) (случай унарной операции); б) w имеет двух предшественников, υχ и ν2, являющихся корнями деревьев T(vt) и Τ(ν2) соответственно (случай бинарной операции). Будем считать, что минимаксные сечения деревьев Τ (ν), Τ(υχ) и Τ(ν2) найдены и равны соответственно s, s± и s2. Секрет алгоритма раскрывает следующая далее Теоремаб. В принятых обозначениях минимаксное сечение s' формулы, задаваемой деревом T(w), в случае а) равно s, а в случае б) выражается формулой (max (sx, sz), если st φ s2, Ui + 1, если51 = 52. Упорядочение вершин дерева T(w), достигающее минимаксной ширины (оптимальное упорядочение), строится следующим образом: в случае а) берется оптимальное упорядочение дерева Τ{ν)Ύ за ним — вершина w; в случае б) берется оптимальное упорядочение дерева с большей, минимаксной шириной (или любое дерево в случае равных ширин),, га ним — оптимальное упорядочение другого дерева, за ними — вершина w.
§ 3.3. РАСКРАСКА ВЕРШИН ГРАФА. ОБЩЕЕ ИССЛЕДОВАНИЕ 123 Доказательство. Случай а) тривиален, так как, имея оптимальное упорядочение дерева Τ (ν), мы его наращиваем заключительной вершиной w однозначно, ширина добавленного сечения равна единице и не может быть больше уже достигнутой минимаксной ширины 5. Рассмотрим случай б). На рис. 3.9, а) схематически показано упорядочение дерева T(w) без смешивания порядков T(vx) и Γ(ι?2), а на рис. 3.9, б) — со смешиванием. Очевидно, что если st > 52, то упорядочение, требуемое условием теоремы, будет оптимальным, так как информационные связи деревьев Τ(νλ) и Τ(ν2) при упорядочении без смешивания не конкурируют, а достигаемая ширина, равная 92 + 1 в одном из сечений при вычислениях на дереве Τ(υ2), не превзойдет ширины s1? как раз и являющейся по теореме минимаксной шириной всей формулы. Если же sx = s2, то минимаксной шириной оказывается Sjl+1. Любое же упорядочение со смешением порядков T(vx) и Τ(ν2) может лишь увеличить ширину, достигаемую при упорядочении согласно условию теоремы, так как при этом в дополнение к новой связи от l?! к w становятся конкурирующими некоторые связи внутри деревьев . Τ(νλ) и T(v2). VV На основе доказанной теоремы алгоритм оптимального упорядочения приобретает следующий вид. Сначала на вершинах деревьев строится по индукции функция ширины. Для висячих вершин она с очевидностью полагается равной единице, а затем, по правилу теоремы, находится для очередной вершины дерева, используя уже найденные значения функции ширины ее предшественников. Затем дерево упорядочивается от корня к висячим вершинам: взяв корень, ставим перед ним его единственного предшественника (для случая одноместной операции). В случае двух предшественников νχ и ν2 ставим перед корнем вершину νχ (если $г < .92), а вершину ν2 запоминаем. Затем «корнем» становится вершина ι\, и все повторяется, пока не дойдем до висячей вершины. Поместив на место висячую вершину, берем в качестве «корня» последнюю из запомненных вершин. На рис. 3.10 приведены два /пп 5/ Λ [ !\1 Vl \ ϋ Ι а h υζ ! Д DD а) S) Рис. 3.9. К доказательству теоремы 6 а) Упорядочение без смешивания. б) Упорядочение со смешиванием.
124 ГЛ. 3. АЛГОРИТМИЗАЦИЯ W а очен упоряд о (-Н О Η а S В £< с · о о η дере ольпое β со в о ей t vo Λ · л Ь4 И 2 си ч к >> ее Q, И О со Р* <§г=—^—*Θ*—*& ■Θ*
§ 3.3. РАСКРАСКА ВЕРШИН ГРАФА. ОБЩЕЕ ИССЛЕДОВАНИЕ 125 результата оптимального упорядочения: один — для дерева формулы вычисления я59, другой — более сложный (римскими цифрами указаны значения функции ширины, арабскими — оптимальный порядок в обратной нумерации)*). Оценки числа тагов. Для основной нити нашего изложения этот пример поучителен формой алгоритма, решающего поставленную комбинаторную задачу. Наиболее важным свойством этого алгоритма является его направленность. С одной стороны, мы по существу используем информацию, заложенную в дереве формулы, являющуюся «материалом» нашей задачи. Нам надо «пройти» каждую вершину и «обработать» каждое бинарное отношение, образующее ту или иную дугу дерева. Мы замечаем разницу между висячими и прочими вершинами. С другой стороны, в работе алгоритма можно усмотреть некоторое единое направление его развития: сначала от висячих вершин к корню при построении функции ширины, а затем — наоборот, при упорядочивании. Если мы и откладываем некоторые вершины «про запас» (запоминание вершин с большим значением функции ширины), то и это мы делаем систематически: мы не рыскаем произвольно среди них, а берем всегда вершину, запомненную последней. Для математического рассмотрения нам, однако, недостаточно такого интуитивного представления об эффективности алгоритма, которое мы выражаем только словами: переборный алгоритм, направленный алгоритм и т. п. Роль критериев эффективности алгоритмов играют уже упоминавшиеся оценки сложности алгоритма. Мы уже знаем, что каждая программа характеризуется числом команд и объемом расходуемой памяти. Заметим, что число команд можно понимать двояко: как число команд в программе, так и число выполнившихся команд при выполнении программы. В ряде разделов математики и программирования первая характеристика тоже важна, однако эффективность программы лучше характеризуется вторым показателем. Аналогичные характеристики рассматривают и для алгоритмов. Если зафиксировать способ описания алгоритма (алгоритмический язык), точно описать, как данные размещаются в памяти, то тогда, выполняя алгоритм для некоторых исходных данных, можно точно посчитать или оценить как число элементарных шагов выполнения алгоритма, так и число единиц информации, которое надо одновременно размещать в памяти. Если исходные данные имеют некоторый характеризующий их параметр (порядок матрицы, число вершин или дуг в графе, количество независимых перемеиных и т. п.), то тогда и подсчитываемое или *) Для читателей, которые заинтересовались алгоритмом оптимального упорядочения самим по себе, заметим, что попытки его обобщения на линейные программы с более сложными, чем деревья, информационными связями наталкиваются на большие трудности.
i26 ГЛ. 3. АЛГОРИТМИЗАЦИИ оцениваемое число шагов и объем памяти становятся функциями этого параметра. Эти функции и называют показателями или щенками сложности алгоритма (или программы). Оценки числа шагов называют временными оценками, оценки числа требуемых ячеек памяти так и называются оценками памяти, или емкостными оценками. Обычно в качестве параметра, характеризующего исходные данные алгоритма, берут некоторое натуральное число и, как-то -связанное о их объемом. Тогда эффективность алгоритмов по времени их работы сопоставляют со скоростью роста временной оценки как функции F(n). В этой градации скоростей роста различают .прежде всего следующие функции: F(ri) = η — линоаная оценка, F(n) = η \oga n — логарифмическая оценка, F(n) = η2 — квадратичная оценка, F(n) = а0пк +a17ift—ljr - - . -|- a*""" — полиномиальная оценка, F(n) = an —экспоненциальная оценка, F(n) = n\ — факториальная оценка, F(n) = nn — гиперэкспоненциальная оценка. Каждая из указанных функций задает на самом деле целую серию оценок данной скорости роста, отличающихся от показанных выражений коэффициентами при η или при самой функции. Если η характеризует число «независимых переменных» в исходных данных, то в силу приведенного выше рассуждения линейные оценки характеризуют самые быстрые алгоритмы, которые затрачивают на каждый элемент исходных данных ограниченное константой количество действий. Примером алгоритма с логарифмической оценкой являются некоторые алгоритмы упорядочения η чисел. Алгоритмы с полиномиальной (в частном случае квадратичной) оценкой считаются крайним случаем «практичных» алгоритмов, тогда как алгоритмы с более высокими оценками применяются только для малых значений п, а для больших значений заменяются «приближенными» алгоритмами, дающими в какомтто смысле приблизительное решение задачи с приемлемой временной оценкой (по возможности не более чем квадратичной). Особая роль квадратичной оценки выясняется из следующего интуитивного рассуждения. Линейная временная оценка означает, что в таком алгоритме каждая входная переменная вносит свой вклад в результат независимо от других. Типичный пример — суммирование чисел. Здесь то, что мы назвали направленностью алгоритма, выступает в своем чистом виде: выполнив несколько операций над входной переменной, мы к ней больше не возвращаемся. Квадратичные оценки появляются тогда, когда вклад
§ 3.3. РАСКРАСКА ВЕРШИН ГРАФА. ОБЩЕЕ ИССЛЕДОВАНИЕ 127" каждой входной переменной в результат существенно зависиг от ее «взаимодействия» со всеми, или почти со всеми, другими переменными. Читателю может показаться странным, но ему будет не очень просто сразу придумать задачу, которая, по существу,, требовала бы для своего решения алгоритма с квадратичной оценкой. Первое, до чего додумался автор', размышляя над этими строками,— это построение многочлена, принимающего заданные п. значений (такие многочлены называются интерполяционнымиг и кто-нибудь из читателей знает про многочлены Лагранжа,, удовлетворяющие такому требованию). Там, для заданных значений многочлена хи х2, . . ., хп, нужно вычислить все возможные* их разности xt — Xj (i, / = 1, · · ·, я), что и даст квадратичную* оценку. Вернемся теперь к нашей задаче. Для того чтобы связать ее> с только что проведенными рассуждениями, нам надо договориться о том, что характеризует «независимые переменные» и их число в исходных данных и «единицу действия» в алгоритмах раскраски. Мы уже оценивали комбинаторный объем различных раскрасок: как функцию числа η вершин графа. Мы можем полностью описать граф, если для каждой вершины указать множество реберт которым она принадлежит, или, что то же самое, множество смежных ей вершин. Такое описание «ближайшего окружения» вершины или, как мы будем говорить, окрестности 1-го порядка мы иг будем считать «единицей информации» в задании графа. Конечног. строго говоря, ее нелизя по-настоящему считать единицей информации, так как ее объем весьма различен. Изолированная вершина имеет пустую окрестность 1-го порядка, а «звезда», т. е. вершина графа, смежная со всеми остальными, содержит в этой окрестности вершины всего графа. Общий объем этой информации тоже* весьма различен при фиксированном п: от нуля ребер в графе,, состоящем из изолированных вершин, до η — 1 ребра в самом простом связном графе (незамкнутая цепочка из η вершин) ит наконец, до п(п — 1) ребер в η-полном графе (в котором все гг вершин попарно смежны). Тем не менее для прикидочных рассуждений об эффективности алгоритмов раскраски, когда мы неделаем никаких дополнительных предположений о способах представления графов, такая трактовка единицы информации для нас пока достаточна. Там же, где нам удастся вставить в рассуждение число ρ ребер графа, мы будем также использовать его в* качестве параметра задачи. При таком подходе естественно рассматривать в качестве «шага» алгоритма раскраски совокупность действий, относящихся к вершине и ее окрестности 1-го порядка. Если же нам требуется большая детальность, то тогда одним шагом может стать «отработка» одного ребра графа, например, проверка, какой краской. окрашена смежная вершина.
128 ГЛ. 3. АЛГОРИТМИЗАЦИЯ § 3.4. Раскраска вершин графа. Поиск алгоритма Итак, мы приступаем к поискам практичного алгоритма раскраски вершин графа, сознавая, что минимальные раскраски в общем случае требуют экспоненциального числа шагов. Это означает, что нам придется подойти к построению алгоритма с другого конца: отказавшись от претензии на нахождение заведомо минимальных раскрасок, мы задаемся некоторой общей организацией алгоритма, обеспечивающей приемлемую временную оценку, но в рамках этой организации постараемся действовать каким-то разумным способом, конкретизирующим общий принцип здравого смысла: «поступай наилучшим образом в пределах возможного». Рамки возможного и то, что считается наилучшим, это и есть содержание того конкретного анализа нашей задачи, который мы пытаемся предпринять. Эвристические методы. Человеку в повседневной жизни постоянно приходится сталкиваться с ситуациями, которые в их математическом выражении выглядят как комбинаторные задачи, требующие непомерных затрат на поиск абсолютно наилучшего решения и поэтому заставляющие вырабатывать какую-то ограниченную тактику поиска приемлемого решения. Вот примеры таких правил: — не отменяй принятых решений; — упаковывая вещи в чемодан, начинай с самых громоздких предметов; — в поисках, максимума функции двигайся в направлении градиента; — лучше синица в руках,-чем журавль в небе; — не зная, как поступить, поступай как-нибудь. Пусть читателя не смущает «ненаучный» вид этих изречений. В каждой точно описанной комбинаторной задаче эти правила можно одеть в самую изысканную математическую одежду, но это не изменит их сути, которая, особенно на начальной стадии поиска алгоритма, гораздо лучше выражается в таком виде, проникающем непосредственно в подсознание — этот реактор творчества человека. Догадка и интуиция играют в нахождении и формулировании правил такого рода не меньшую роль, чем точное знание и логическое рассуждение. Не случайно правила приближенного решения комбинаторных задач называют эвристическими — от греческого восклицания heureka (я нашел!), ставшего со времен Архимеда одним из наиболее известных научных терминов. Особенностью любого эвристического метода решения задачи является наличие контрпримеров, показывающих неэффективность или неприемлемость этого метода при поиске идеального решения. Мы, однако, сознательно примиряем себя с их существованием, веря, во-первых, что эти контрпримеры не слишком портят, нам
§ 3.4. РАСКРАСКА ВЕРШИН ГРАФА. ПОИСК АЛГОРИТМА 129 общую картину, и полагая, во-вторых, что любые попытки преодоления этих особых случаев нам обойдутся дороже, чем достигаемый этим выигрыш. В то же время поиск и анализ таких контрпримеров должен быть неотъемлемой частью всякого честного исследования, чтобы лучше понимать как силу, так и границы применимости эвристических методов. Эвристика раскраски. В нашей задаче стремление найти алгоритм раскраски с не более чем квадратичной временной оценкой означает, что мы можем потратить на окраску одной вершины не более чем порядка η шагов. За η шагов мы можем осмотреть любую окрестность вершины, но не более чем весь граф. Такой экономный режим работы побуждает нас так организовать алгоритм раскраски, чтобы не перекрашивать вершип, а на основе некоторого анализа окрестности вершины или, быть может, всего графа красить вершину, «не отменяя впоследствии принятых решений». Этот, казалось бы, почти тривиальный подход уже задает некоторую дисциплину алгоритма: нам теперь надо решить, в каком порядке просматривать вершины графа и какой анализ (окрестности или всего графа) производить, чтобы распорядиться выбором краски для вершины. «Краска и вершина» — наличие этих двух объектов подсказывает двойственный подход к общей организации раскраски. Первый — это взять некоторую краску и красить ей по какому-то выбору вершины, пока не окажется ни одной вершины, которой можно было бы сопоставить эту краску. Второй подход — мы просто повторяем конец предыдущего абзаца — состоит в том, чтобы, рассматривая вершины в некотором порядке, выбирать для очередной вершины подходящую краску. Мы еще плохо понимаем, в чем состоит разница между первым и вторым подходами, и кому-нибудь эти перефразировки покажутся просто игрой слов. Однако потребность логического анализа любой ситуации, присущая каждому математику, толкает нас на то, чтобы немного чшоиграть» с этими вариантами. Рассмотрим некоторое промежуточное состояние алгоритма раскраски для каждого из этих подходов. Для того чтобы сделать 'очередной шаг и раскрасить очередную вершину мы, в частности-, должны определить, каковы ограничения (чего нельзя делать) и каковы степени свободы (чем можно распорядиться). При первом подходе — это определение на каждом шагу множества V' нераскрашенных вершин, которым нельзя сопоставить текущую краску α и множество V нераскрашенных вершин, которым можно сопоставить краску а. Очевидно, что V — это вершины, которые смежны хотя бы с одной из вершин, окрашенных краской а, и только они (будем обозначать такое множество V(a)). V" — это, стало быть, (V\CV)\V\ где V — множество всех вершин графа, CV — множество раскрашенных вершин к данному мо-
130 ГЛ. 3. АЛГОРИТМИЗАЦИЯ менту. В частности, условие промежуточного финиша, т. е. исчерпания возможностей для дальнейшего использования краски α — это Υ" = 0. Общее окончание работы — это обнаружение, ЧТо V = CV. Во втором подходе анализ ограничений имеет дело с окрестностью Ri(v) 1-го порядка текущей вершины ν, τ. е. множества смежных с ней вершин. Ни одна из красок, сопоставленных вершинам из R^v), не годится для v. В степенях свободы при раскраске вершины ν есть две градации: одна — это какую краску выбрать из уже использованных, и вторая — взятие «свежей»- краски. После этих двух абзацев разница между двумя подходами стала более ощутимой. Первый алгоритм кажется более направленным: на каждом шагу нам надо просто выбрать вершину из У" или взять свежую краску, если У" пусто. Однако получение Vr и У" требует более глобальных операций над графом: манипуляций с множеством F(a), со всеми окрестностями 1-го порядка era вершин, с множеством СУ и V. Второй алгоритм локализует анализ в окрестности R^v), но предоставляет более расплывчатые альтернативы. Очевидно, наше внимание теперь привлекает вопрос, а нельзя ли каким-то образом улучшить анализ в первомг алгоритме, который мы производим, отправляясь от множества V(a). V(a) принадлежит CV и, стало быть, является, так сказать,, «отработанною) частью графа. Все вершины из V(a) попарно не смежны. Нас интересует для последующих решений только характер связей вершин V(a) со смежными им вершинами. Эту ситуацию можно вообразить в виде картинки на рис. 3.11, а). При таком изображении (автор надеется) естественно появляется мысльг что если «склеить.» вместе вершины из F(a) так, как это показано- на рис. 3.11, б), то тогда V становится просто окрестностью 1-го порядка новой вершины w. Каждый согласится, что это уже лучше, но для того, чтобы склеить вершины V(i), их все равно нужна перед этим собрать все вместе. Но тут уже начинает работать обычная сообразительность: на предыдущих этапах использования краски α мы по очереди держали «в руках» все вершины из 7(a): имея очередную вершину ν, окрашенную краской а, мы находили пополнение υ' в семью F(a), черпая ее из F". Так вот в этот-та момент мы и склеим ζ; с ζ/ и будем поступать так всегда, превращая процесс назначения краски вершине в последовательность попарных склеиваний несмежных вершин. Еще не разобравшись до конца, что такое склеивание, основываясь на наглядном представлении об этом, взятом из картинки, отрабатываем эту идею* до конца. Представим, как будет развиваться процесс с начала,, т. е. с работы с первой краской ссх. Множество CV в начальный; момент пусто. На каждом шаге склеивания V" = (F\S3J(^1))\ \{ι?χ}, где vx — это вершина, в которую мы «вклеиваем» вышины.
§ 3.4. РАСКРАСКА ВЕРШИН ГРАФА. ПОИСК АЛГОРИТМА 131 раскрашиваемые краской av Промежуточный финиш состоится, когда V" = 0, откуда следует, что {vx}[] Rx{vx) = F, т. е. когда вершина vx становится звездой. Если мы после этого начнем работать со второй краской а2, начав вклеивать покрашенные ею вершины в некоторую вершину v2, то, так как v2^R1(v1), множество CV = {г;,} становится автоматически подмножеством Rx(v2)9 откуда мыполучаем, что и для ν2 V" = (V\flj(i;2))\{i;2}. Немного' /; S) Рис. 3.11. Склеивание вершин· графа. а) До склейки, б) После склейки. поразмыслив, мы обнаруживаем, что правило выбора множества V" и условие промежуточного финиша (очередная вершина после серии склеиваний становится звездой) сохраняются для любой очередной краски. Очень любопытно звучит теперь и условие окончания работы алгоритма: для каждой вершины ν графа Rx(v)[} {ν} = V, где, однако, V — это уже не множество вершин исходного графа, а, выражаясь языком высокой математики, множество гомоморфных образов вершин исходного графа, так как каждая вершина результирующего полного графа (вспомните его определение!) есть совокупность склеенных попарно несмежных вершин исходного графа. Склеивание вершин. Теперь нам надо остановиться и подумать как следует. Мы не просто нашли некоторую наглядную переформулировку первого подхода к алгоритму раскраски, а ввели в некотором смысле совершенно новую трактовку процесса раскраски вершин. Вместо раскраски мы осуществляем последовательные преобразования графа G, состоящие в «склеивании» несмежных вершин. Склеивание двух вершин νχ и ν2 с окрестностями Rx(vx) и Rx(v2) состоит в устранении из графа вершиц vx и v2 вместе
132 ГЛ. 3. АЛГОРИТМИЗАЦИЯ с инцидентными им ребрами и добавления новой вершины ι? и инцидентных ей ребер таким образом, чтобы R^v) = Я^) (J/?χ(ι;2Κ Результирующий граф G' имеет на одну вершину меньше, а такжо может иметь меньшее число ребер. Меньшее число ребер получается потому, что если для вершин νχ и ν2 существует третья вершина ν3, смежная кай с vv так и с v2, то вместо двух дуг (vl9 v3) и (v2, v3) в графе С останется только одна (ν, и3). Так происходит* если νχ и ν2 находятся друг от друга, как говорят, на расстоянии 2, если измерять расстояние между вершинами графа как число ребер в кратчайшем пути, соединяющем эти вершины. Это можно выразить еще и такими словами, как то, что ν2ΕΞ е R2(v±) и, наоборот г г^еДгО^)» понимая под: окрестностью 2-го порядка некоторой вершины множество всех вершин, находящихся от данной на расстоянии 2. Вершину ν3 естественно при этом назвать вершиной, разделяющей νχ и ν2. Уменьшение числа ребер на одно будет иметь место» для любой вершины,. после Ряс. 3.12. Примеры склеиваний. а) С исчезновением ребер, б) Без исчезновения ребер. Таким образом, можно· заключить, что уменьшение числа ребер графа G будет· иметь место только при склеивании вершин, находящихся на расстоянии 2, при этом число исчезающих ребер равно числу разделяющих вершин. Все, что мы сейчас написали, есть просто аккуратное наблюдение процесса склеивания вершин, которое, быть- может, пригодится нам в будущем. Для читателей, любящих наглядность, мы покажем на рис. 3.12 два варианта склеивания вершин, а для педантичного читателя подчеркнем, что мы определяем понятие разделяющей вершины только для вершин, находящихся друг от друга на расстоянии 2. возвращаясь к последовательным склеиваниям, мы обнаруживаем, чю преобразования каждого очередного графа G продол-
§ 3.4. РАСКРАСКА ВЕРШИН ГРАФА. ПОИСК АЛГОРИТМА 133 жаются до тех пор, пока в нем не окажется ни одной пары несмежных вершин, т. е. пока G не окажется некоторым ϋΓ-полным графом. Очевидно, что Z-полный граф допускает только одну тривиальную раскраску: каждая из К вершин υ красится своей краской, которая одновременно оказывается краской для всех вершин исходного графа, вклеенных в v. Поскольку все они попарно не смежны, такая раскраска оказывается допустимой, при этом порядок К результирующего полного #-графа есть число красок. Задача получения минимальной раскраски становится задачей построить такую последовательность склеиваний вершин исходного графа (еще одно замечание для любителей строгости: говоря о преобразовании исходного графа G в другой граф G' мы тем пе менее можем «узнавать» в «другом» графе вершины исходного графа, при этом неважно, склеенные или не склеенные друг с другом), при котором порядок результирующего /^-полного графа будет минимальным среди всех возможных, другими словами, будет равен x(G) (напоминаем: χ(6?) — хроматическое число графа G). Продолжая наш анализ, мы усматриваем, что трактовка раскраски как попарного склеивания годится вполне и для второго подхода к алгоритму раскраски. Здесь мы тоже ищем какую-то пару неемежных вершин и склеиваем ее. Разница между первым и вторым подходом теперь лишь в том, что в первом подходе мы вклеиваем все возможные вершины в одну, пока она не станет звездой, а во втором подходе мы, задавшись заранее некоторым порядком вершин, идем от одной вершины к другой, подыскивая ей подходящего напарника для склеивания. Сводя раскраску вершин графа к их последовательному склеиванию, нам нужно убедиться, что на этом пути мы не утрачиваем потенциальной возможности получить минимальную раскраску исходного графа. Конечно, можно сразу сообразить, что если взять некоторую минимальную раскраску в X красок и склеить между собой все вершины, окрашенные одним цветом, то в результате у нас получится χ-полный граф, однако на самом деле нам требуется более сильное утверждение, которое мы оформим в виде теоремы. Теорема 7. Для всякого графа с хроматическим числом χ существует последовательность попарных склеиваний вершин, приводящая к %-полному графу. Доказательство. Назовем две вершины графа G со- цветными, если существует минимальная раскраска вершин графа G, в которой эти вершины окрашены одной краской. Л е м м а 1. В любом неполном графе G существует по крайней мере пара соцвещных вершин. Пусть в графе G содержится η вершин. Если ни в одной минимальной раскраске нет двух вершин, окрашенных одной краской, значит, %(G) = п. Так как G — неполный граф, в нем есть хотя бы
134 ГЛ. 3. АЛГОРИТМИЗАЦИЯ пара несмежных вершин vt и v2. Склеим эти две вершины. Получившийся граф G' будет иметь η — 1 вершину, а стало быть, %(G') <С η — 1. Взяв любую раскраску графа G' в η — 1 краску или менее, найдем в ней вершину, в которую были склеены vt и и2. Расклеив эти вершины «обратно», сохранив на их следы краски из раскраски С, получим раскраску графа G в η — 1 или менее красок, что противоречит предположению χ((ϊ) = п. ν ' Лемма 2. Если граф G' получается из графа G склеиванием пары соцветных в нем вершин, то %(G') = %(G). Действительно, взяв минимальную раскраску графа G, в которой указанные вершины окрашены одной краской, и сохранив как эту краску на вершине графа G'', получившейся после склеивания, так и краски на остальных вершинах, получаем раскраску графа G' в χ(6?) красок. Отсюда имеем, что %(G') ^ %(G). Неравенство же x(G') <^ %(G) не может выполняться в силу рассуждения, проведенного в доказательстве леммы 1. V На основе этих двух лемм получаем нужную последовательность склеиваний: в исходном графе G ищем пару соцветных вершин и склеиваем. В силу леммы 2 мы «не испортили» граф в том смысле, что его хроматическое число осталось неизменным. В силу леммы 1 такое склеивание можно делать до тех нор, пока очередной граф не станет полным. Опять-таки в силу леммы 2 в нем ке может быть более, чем χ(£) вершин. VV На этом можно считать законченным поиски общей организации алгоритма раскраски. Если бы мы умели легко находить соцветные вершины, то у нас был бы способ получения минимальных раскрасок. Мы еще не имеем прямого подхода к этому, но именно на это сейчас будет нацелен поиск подходящей эвристики выбора склеиваемых нар вершин. Теорема о соцветности. Еще одно авторское отступление перед кульминацией нашего исследования. Деловой читатель, мгновенно усвоив основные определения и последующие за этим абзацем конкретные конструкции алгоритма, может счесть предыдущие несколько страниц каким-то невнятным текстом, тривиальными переформулировками, топтанием на месте. Автор хочет защитить эту часть изложения. В меру своих литературных способностей он хочет показать ту подспудную работу, которую совершает исследователь в поисках решения. Во время таких хождений вокруг да около созревают идеи и наблюдения «второго плана», которые как раз-то и обеспечивают успех дела, когда найденный алгоритм или доказательство нанизывает эти предварительные находки на стержневую ось рассуждения или действия. На самом деле в нашем, может быть, расплывчатом и повторяющемся изложении мы незаметно собрали все, что нам нужно для эффективных алгоритмов раскраски. Вот ключевые идеи и наблюдения:
§ 3.4. РАСКРАСКА ВЕРШИН ГРАФА. ПОИСК АЛГОРИТМА' 135 — направленность раскраски (не перекрашивать вершины); — отказ от гарантии получения минимальной раскраски; — понятие окрестности вершины 1-го и 2-го порядков; — раскрашивание как склеивание вершин; — разделяющие вершины как источник склеиваемых ребер. Сейчас мы покажем, как они, взаимодействуя друг с другом, помогут решить нам проблему раскраски. Мы начнем,с рассмотрения одной замечательной теоремы. Теорема 8. Для любой вершины ν связного графа G, не являющейся звездой, в окрестности R2(v) имеется по крайней мере одна соцветная вершина. Доказательство. Будем иллюстрировать рассуждение рис. 3.13, показывающего вершину ν и ее окрестности ϋχ(ν) • -красках + -κραοκαβ Рис. 3.13. Случаи доказательства теоремы 8. и R2(v). Читателю легко проверить, что если в связном графе вер* шина — не звезда, то ее окрестности 1-го и 2-го порядков не пусты. Рассмотрим некоторую минимальную раскраску графа G, в которой ν получает краску а. Если в этой раскраске некоторая вершина w из R2(v) тоже получает эту краску (рис. 3.13, а)), то теорема выполнена. Рассмотрим теперь случай, когда ни одна вершина из R2(v) не имеет краски а. Возьмем в этом случае любую вершину w из R2(v), окрашенную некоторой краской β, и сосредоточим наше внимание на окрестности Rx{v). Здесь опять-таки возможны два случая. Если ни одна из вершин, принадлежащих R\{v), не имеет краски β (рис. 3.13, б)), то тогда ничто не мешает нам перекрасить ν краской β, добившись тем самым выполнения теоремы. Наконец, возможен случай, когда в Rx(v) есть несколько вершин, окрашенных в β. Обозначим эту подокрестность вершины ν через R'. Заметим, что для любой вершины u^Rx{v) ее окрестность Rx{u)c^ {v} U Rx(v) (J R2(v) (рис. 3.13, в)). Отсюда становится
136 ГЛ. 3. АЛГОРИТМИЗАЦИЯ ясным, что для любой вершины из Λ' вершина ν является ее единственной смежной вершиной, окрашенной краской а. Снимем «на минуту» краску α с вершины v. Тогда нам ничто не мешает перекрасить все вершины из R' в краску а, убрав тем самым краску β из окрестности R^v). В таком случае красим вершину и в краску β, получив раскраску, удовлетворяющую условию теоремы. VV Важность этой теоремы для нас очевидна. Она позволяет существенно ограничить область поиска соцветных вершин, гарантируя возможность найти соцветную вершину в пределах окрестности 2-го порядка рассматриваемой вершины. Мы уже получаем некоторую ориентацию: даже если мы будем склеивать вершины в графе наудачу, мы будем иметь больше шансов на успех, если ограничим наш произвол окрестностями 2-го порядка. Ограничение, требующее связности графа, нас, по-видимому, не смущает: будем красить каждую компоненту отдельно одними и теми же красками. Читатель может сразу проверить эффективность этой эвристики (склеивать с любой вершиной, находящейся на расстоянии 2), нарисовав серию графов и раскрасив их таким способом. Для ориентации на рис. 3.14 приведен граф, нарисованный в свое время автором наудачу с единственным условием, чтобы он был плоским. Здесь мы опять немного отвлечемся, чтобы сделать ряд практических замечений к поиску примеров на раскраску графов. Нам желательно знать, насколько хороши наши раокраски. В некоторых случаях известен принципиальный нижний предел числа красок для графов того или иного вида (оценка снизу). В частности, для плоских графов, т. е. которые можно изобразить на плоскости без пересечения ребрами друг друга, известно, что их хроматическое число не больше пяти, но и не меньше четырех (смыкание этих оценок и есть знаменитая, не решенная до сих пор проблема «четырех красок»). Далее, если граф содержит в себе в качестве подграфа тг-полный подграф, то число красок никак не может быть меньше п. Рис. 3.14. Удачное применение 1-й эвристики.
§ 3.4. РАСКРАСКА ВЕРШИН ГРАФА. ПфИСК АЛГОРИТМА 137 ε) Так вот, если взять граф с рис. 3.14 и раскрасить его по эвристике, подсказанной теоремой 8 (мы будем называть это 1-й эвристикой), то, следуя заданной нумерации вершин (начиная с 1-й вершины и в ее окрестности склеивая с вершиной с наименьшим номером и обозначая результат склеивания меньшим из двух рассматриваемых номеров), мы получим раскраску этого графа в три краски, показанные на-фигуре римскими цифрами. Тот факт, что эта эвристика нетривиальна, показывает уже простейший пример рис. 3.15. Исходный граф — это шестиугольник с четным числом вершин и (вспомним §3 из 1-й главы), хроматическим числом, равным двум. Склеивание вершин, находящихся на расстоянии 3, приводит к появлению треугольников (рис. 3.15, а)), и, стало быть, к увеличению хроматического числа, в то время как склеивание по правилам 1-й эвристики сохраняет его (рис. 3.15, б)). Этот же пример помогает нам понять, как можно было бы додуматься до только что доказанной теоремы. Назначение краски α на вершину ν образует вокруг нее «мертвую зону» ϋχ(ν), где краска α уже не может быть использована. Минимальность раскрасйц означает, что на каждую краску приходится «наибольшее» количество вершин. Увеличение числа вершин, окрашенных данной краской, ведет к росту мертвых зон. Когда эти зоны охватят весь оставшийся граф, данной краске уже нет места для использования. Мы будем получать выигрыш, если мертвые зоны, расползаясь по графу, будут по возможности больше перекрываться. Перекрытие мертвых зон двух несмежных вершин имеет место только тогда, когда они находятся на расстоянии 2, а степень перекрытия определяется числом разделяющих вершин. Так мы приходим к идее теоремы 8. Напомним тем, кто не забыл своего детства, что аналогичную ситуацию мы имеем в игре в морской бой. Там каждый выбитый корабль показывает противнику аналогичную мертвую зону — δ) О 1-й Рис. 3.13. Пример нетривиальное™ эвристики. а) При склеивании появляются треугольники, б) Хроматическое число сохраняется.
138 ГЛ. 3. АЛГОРИТМИЗАЦИЯ смежные клетки, где нельзя ставить корабли. Любой искушенный игрок знает, что если поставить корабли просторно — вдали от стенок и друг от друга, то его флот будет быстро выбит, так как даже если в начале игры они понесут равные потери, его противник на будущее будет иметь в своей акватории существенно больший запас пространства, не покрытого выстрелами. Оценка хроматического числа. Доказанная теорема дает нам не только обнадеживающую эвристику, но и простую оценку числа красок, расходуемых при раскраске по 1-й эвристике. Эту верхнюю оценку мы получим как функцию числа вершин η и ребер ρ связного графа. В основе получения оценки будет лежать тот факт, что при склеивании вершин, находящихся на расстоянии 2, из графа исчезает хотя бы одно ребро (имеется хотя бы одна разделяющая вершина). Легко сообразить, что в связном графе число ребер ρ удовлетворяет следующим неравенствам: л ^ η (η — 1) и — 1</?<—^-g—. Максимальное число ребер характеризует тг-поляый граф. Рассмотрим теперь процесс склеивания вершин. Мы склеиваем вершины одну за другой, пока не получим некоторый fc-полный граф (к < ή). Он будет иметь к(к — 1)/2 ребер. Так как при склеивании вершин, находящихся на расстоянии 2, из графа удаляется по крайней мере по одному ребру, то в итоговом графе число ребер будет меньше исходного. Число исчезнувших ребер s =з ρ — к(к — 1)/2. В силу сделанного замечания s > η — к, Где (ji — ]ή — общее число склеиваний. Отсюда получаем неравенство к (к — 1) . 7 ρ у—^—L^n— к, которое после простых преобразований приобретает вид /с2 — 3fc — 2(p — тг)<0. (1) Положительный*корень уравнения &, = 3+г 9 + 8(р — п) Отсюда мы видим, что любое положительное &, удовлетворяющее уравнению (1), не должно превышать целой части от fc+, откуда мы получаем следующую оценку хроматического чясйа χ (G%) л числа красок /*i(G£), получающегося при раскраске по первой эвристике (Gn — связный граф, имеющий η вершин и ρ ребер) »(ca<*i(Cg)<[8 + V9+28(l>-")]. (2) В упрощенном виде, показывающем лишь степень роста оценивающей функции, оценка имеет вид hx (ϋζ) « 3>Υ~(ρ — η) /2.
§ 3.4. РАСКРАСКА ВЕРШИН ГРАФА. ПОИСК АЛГОРИТМА" 139 Пользуясь этой формулой, можно наглядно представить оценку эффективности описанного алгоритма раскраски в виде графика. Поскольку оценка является функцией двух переменных, мы приведем график h, как функции η (охватив диапазон более или менее реальных масштабов задачи раскраски в интересах экономии памяти от η = 50 до η = 500), взяв для ρ случай «плотных» графов, когда р, скажем, лишь вполовину не дотягивает до числа ребер полного графа: ρ = —у—, и случай более разряженных графов, когда число ребер пропорционально числу вершии, например, 50 100 200 500 400 500 π Рис. 3.16. Эффективность 1-й эвристики ρ = 10-п. Полученный график показывает (рис 3.16), что экономия памяти, производимая раскраской графа несовместимости, может быть весьма существенной. Об исчезающих ребрах. На этом, однако, наша эксплуатация теоремы о со цветных вершинах не оканчивается. Ход рассуждений при доказательстве верхней оценки хроматического числа как функции числа вершин и ребер связного графа позволяет нам еще раз взглянуть на проблему раскраски в целом. В чем состоит раскраска? В последовательности склеивания вершин графа. Когда она завершается? Когда при склеивании получится полный граф. Чем он характеризуется? Максимальным отношением числа ребер к числу вершин, равным (к — 1)/2. Во всех неполных графах это отношение меньше. Почему процесс склеивания вершин не доходит7 как правило, до предела? (Кстати говоря, каков этот предел для связного графа, имеющего более одной вершины?) Потому, что при склеивании вершин граф становится как бы «гуще», относительная доля ребер увеличивается,
140 гл. з. алгоритмизация достигая в какой-то момент насыщения (к(к — 1)/2 ребер на к вершин). Тем самым мы будем получать тем лучшие варианты 50 40 30 2в 20 /О в 7 J *' О Рис. 3.17. График убывания числа вершин и ребер при склеивании вершин графа. 1 — первая эвристика, 2 — вторая эвристика, S — третья эвристика. раскраски, чем позже допустим образование полного графа при последовательных склеиваниях. Давайте в этом разберемся подт робнее. Будем изображать баланс числа вершин и ребер при
§ 3.4. РАСКРАСКА ВЕРШИН ГРАФА. ПОИСК АЛГОРИТМА 141 склеивании вершин графа в виде графика. По оси абсцисс (рис. 3.17) будем откладывать число к склеиваний вершин. На графике изобразим прежде всего число вершин в графе как функцию числа склеиваний. Это будет функция φ = η — к. Затем для каждого к отложим вдоль оси ординат число ребер, которое имеет полный граф с η — к вершинами. Это будет нисходящая ветвь параболы у = ((п — к)2 — η + к)/2, пересекающая ось ординат в точке п(п — 1)/2 и в точке η — к = 3 пересекающая функцию числа вершин графа (в треугольнике число вершин и ребер равно). Отложим, наконец, на оси ординат число ребер ρ некоторого связного графа G£. При склеивании вершин будем для каждого к отмечать число ребер в получившемся графе. У нас получится своего рода траектория убывания числа ребер. Как только эта траектория уткнется в ограничивающую параболу, процесс склеивания обрывается: мы достигли насыщения. Если при каждом склеивании у нас исчезает ровно одно ребро, траектория будет иметь вид прямой у = ρ — к. Абсцисса к* точки пересечения эт.ой прямой с «параболой насыщения» дает гарантируемую 1-й эвристикой оценку числа красок, равную η — к*. Отсюда сразу напрашивается вывод: ТеоремаЭ. Минимальная раскраска связного графа G получается последовательностью склеиваний, при которой суммарное число исчезнувших ребер оказывается не меньшим этого числа для всех других последовательностей. Этот вывод для нас хорош тем, что он дает разумную опору для более эффективных эвристик: рассматривая окрестность R2(v)t мы не знаем наверняка, какая из вершин является соцветной. Однако если мы выберем из R2(v) вершину w, имеющую с ν наибольшее среди остальных вершин R2(v) число разделяющих вершин, мы обеспечим на данном шагу наибольшее доступное нам убывание числа ребер. Будем называть этот алгоритм 2-й эвристикой. Более точно этот алгоритм выглядит так. Пусть задан какой-то порядок вершин графа. Берем очередную вершину и в ее окрестности 2-го порядка ищем вершину w с максимальным числом разделяющих. Склеиваем и с w, полученную вершину считаем очередной. ПоступавхМ так до тех пор, пока очередная вершина не станет звездой, после чего переходим к следующей по порядку вершине-незвезде и т. д. Рис. 3.18 показывает случай, когда 2-я эвристика (3.18, в) оказывается эффективнее 1-й (рис. 3.18, б), а на рис. 3.19 показан случай, когда вершина, выбираемая по 2-й эвристике, не оказывается соцветной. Во 2-й эвристике мы фиксировали очередную вершину и в ее окрестности искали кандидата на склеивание с максимумом разделяющих вершин. Можно усовершенствовать алгоритм, вводя 3-ю эвристику, не связанную с жестким порядком вершин графа:
142 ГЛ. 3. АЛГОРИТМИЗАЦИЯ перед каждым склеиванием искать в графе пару вершин с мак~ симальным числом разделяющих среди всех пар вершин, находящихся друг от друга на расстоянии два. Пример рис. 3.19 лишает? Рис. 3.18. Пример удачного применения 2-й эвристики. а) Граф. б) 1-я эвристика, в) 2-я эвристика. нас надежд на получение минимальной раскраски и для этой эв-^ ристики, однако в среднем можно надеяться на ее большую эффективность по сравнению с первыми двумя. Правда, это возмож-ι ное улучшение требует, вообще говоря, порядка п2 операций для| выполнения одного склеивания. Рис. 3.19. Пример неудачного применения 2-й эвристики. а) 2-я эвристика, б) Минимальная раскраска. Автором был взят граф из 50 вершин, построенный на ЭВМ случайным образом, лишь бы он оказался связным и содержал: бы 400 ребер. Для этого графа были получены и нанесены на рис. 3.17 три траектории убывания числа ребер, полученные ш> 1-й, 2-й и 3-й эвристикам. Они подтверждают наше интуитивное представление как об их относительной эффективности, так и о приличном «запасе мощности» этих алгоритмов по сравнению с оценкой (2), достигаемой для заданных пир только на графах: довольно специального вида — какого, читателю предлагается: додуматься самому.
ГЛАВА 4 РЕАЛИЗАЦИЯ § 4.1. Вступление В этой главе мы сделаем еще один шаг в конкретизации нашего исследования и в приближении к его завершению. Мы превратим найденные в предыдущей главе алгоритмы над абстрактными объек-' тами в реально выполнимые процедуры. В наших условиях «реальное выполнение» означает выполнение на ЭВМ. Это значит, что алгоритмы должны быть запрограммированы, выраокены на алгоритмическом языке. Мы уже обещали мимоходом, что этим языком будет алгол. Первый и весьма важный этап работы по программированию — это найти подходящие представления для введенных ранее в интересах нашей задачи абстрактных объектов: операторной схемы, информационного графа и его компонент связности, графа несовместимости и его раскраски. Выбор этих представлений подчиняется двум очевидным требованиям: (1) в основе представлений должны лежать объекты алгола: целые и вещественные числа, логические значения и их возможные объединения в массивы; (2) представления должны быть «естественными» для рассматриваемых абстрактных объектов, в частности, в представлении составного объекта должны легко усматриваться представления его компонент. Заметим, что алгол (имеется в виду язык алгол 60) довольно скуден в отношении разнообразия своих объектов и в более современных языках мы могли бы выбрать более естественные представления для некоторых наших абстрактных объектов. Тем не менее алгола 60 хватит для того, чтобы на примере нашей задачи познакомиться с одним из наиболее универсальных способов -«арнфхметизации» абстрактных объектов, т. е. их представления в виде чисел и их комбинаций. В основе этой арифметизации лежит предположение, что все рассматриваемые множества конечны, причем их мощность в момент работы с ними известна. В таком случае все эти множества занумеровываются, после чего в качестве представления элемента множества берется его номер. Тот факт, что в результате такого соглашения элементы самых разных множеств представляются одним и тем же объектом,— целым числом,— никого не бёспо-
144 ГЛ. 4. РЕАЛИЗАЦИЯ коит. Считается, что в любой момент работы программы вы знаете, с номером чего имеете дело: с номером переменной величины, или номером оператора, или номером аргумента. При этом мы будем говорить «элемент i» или <а-й элемент», как нам будет удобнее, заранее понимая, что речь идет об одном и том же. Второе универсальное правило задает способ изображения множеств, являющихся подмножеством некоторого общего занумерованного множества Μ — {т1ч . . ., тп}. В этой символике любое М' с. Μ имеет вид Мг = {пцх, т,\г,..., т^ к ^ О, 1 ^ h ^ п- Тогда для представления берется логический вектор длины п, в котором каждая из компонент с номерами iv i2, . . ., ik равна истина, а все остальные компоненты равны ложь. Во многих задачах вместо логических значений ложь и истина берут соответственно 0 и 1. В литературе такие векторы иногда называются логическими шкалами. В некоторых случаях представление элемента множества должно показывать, элементом какого множества является данное представление. Пусть эти множества суть М19 ДГ2, . . ., tok. Тогда для этих множеств образуется числовое множество {1,. .. . . ., к}, называемое признаковым множеством, а его элементы называются признаками. Признак есть просто номер одного из множеств Mj, . . ., Mk. Тогда т-& элемент множества Мх изображается парой (Z, т). Непосредственное применение этих правил арифвдетизащш будет показано на соответствующих этапах программирования. При построении программ, реализующих экономию памяти в операторных схемах, мы продемонстрируем одну методику программирования, которая в последние годы получила широкое распространение. Эта методика называется «структурированное программирование». Этот термин — не единственный. Даже только в литературе на русском языке можно найти термины «структурное», «систематическое», «детализирующее», «нисходящее» программирование, которые обозначают примерно одно и то же. Схему структурированного программирования мы объясним в следующем параграфе, а пока скажем лишь, какие трудности программирования пытается преодолеть эта методика. В апреле 1975 г. в Лос-Анджелесе (Соединенные Штаты) состоялась международная конференция по программированию. Один из докладов, в котором излагалась сущность структурированного программирования, назывался «Как писать программы правильно и знать об этом?». Здравомыслящему читателю, но не очень близкому к практике программирования, такая тема научного доклада может даже показаться наивностью или кокетством. Однако более тесное знакомство с программированием делает вполне понятной постановку такого вопроса. Составление программы — это предсказание поведения ЭВМ для всех случаев упот-
§ 4.2. СТРУКТУРИРОВАННОЕ ПРОГРАММИРОВАНИЕ 14$ ребления программы, для всего разнообразия входных данных. Если программист составляет программу, скажем, из 1000 команд, работающую на ЭВМ (например, БЭСМ-6) 1 минуту, то это значит, что при написании текста этой программы объемом в 2(У страниц он должен вообразить и точно предсказать выполнение 60 млн. арифметических и логических действий. Ни одна из этих операций не возьмется «неважно откуда», а должна быть явно и недвусмысленно задана программистом наперед. Формально, программа — это текст, состоящий из букв, цифр и знаков. Процесс написания программы можно представить себе как последовательность принятия решений: какую букву напи- сать,*какой знак использовать и т. д. Конечно, буквальная попытка написать программу как текст, скажем, из 10 тысяч символов,, записывая символы слева направо буква за буквой и выбирая 10 000 раз в каждом месте нужный символ из нескольких десятков возможных, может рассматриваться лишь как крайний, теоретический предел процесса принятия решений. Программист пишет программу уже отправляясь от некоторого организованного знания решаемой задачи. Однако на пути передачи машине этого значения стоит очень много преград. Трудность планирования людьми признавалась задолго до появления ЭВМ; эта трудность имеет много общего с уже обсуждавшимися в предыдущей главе комбинаторными сложностями задач выбора вариантов. Такие ходячие выражения, как «Семь раз примерь, один отрежь», «Разделяй и властвуй», «Гладко было на бумаге, да забыли про овраги» имеют множество чисто программистских интерпретаций. В связи с этим поиски лучшей методологии программирования все время были направлены на то, чтобы сделать его как можно более направленным, лишить его непрерывности, создать в процессе написания программы логические паузы, позволяющие «остановиться, оглянуться», отделить локальные мелочи от глобальной информации, сократить возможности для внесения описок или формальных ошибок. Разработка чисто языковых средств — алгоритмические языки, графика блок-схем — эта только составная часть в поисках лучших способов программирования. Мы не будем далее углубляться в общие рассуждения, а коротко рассмотрим одну из таких методик в интересах описания программ экономии памяти. § 4.2. Структурированное программирование В конце 1975 г. в книжных магазинах появилась (и вскоре исчезла) книга У. Дала, Э. Дейкстры и К. Хоора «Структурное программирование». Перевод названия не вполне точен: более правильно говорить «Структурированное программирование»*
146 ГЛ. 4. РЕАЛИЗАЦИЯ Это ближе к английскому оригиналу «Structured programming» и более точно отражает смысл: внесение структуры как в процесс программирования, так и в форму программы. В этой книге содержится основополагающая статья Дейкстры «Заметки по структурному программированию». Он единодушно признается ученым, внесшим наибольший вклад в развитие и распространение структурированного программирования, хотя под другими названиями сходная методика развивалась и другими авторами, а ее математические основы были известны в алгебре рекурсивных функций уже давно, хотя и не использовались на практике. Считая знакомство с этой выдающейся работой необходимым каждому программисту, автор не будет повторять обоснований, а опишет (несколько упрощенно) методику структурированного программирования в применении к конструкциям алгола. Объектом структурированного программирования является «модуль» —частная программа, сочиняемая одним программистом. Программист уже обладает определенной полнотой знания о решаемой задаче, так что проблема состоит лишь в том, как воплотить это знание в конструкцию языка алгол. В частности, его знания достаточно, чтобы точно определить в виде алгольных описаний те объекты (входные данные и конечные результаты), которые нужны для формулирования задачи. Задача программируется либо в виде процедуры (и тогда ее объекты являются формальными параметрами этой процедуры), либо как некоторый блок (или составной оператор) и тогда ее объекты — это те глобальные величины, чьи описания действуют в пределах этого блока. Будем считать также, что задача имеет некоторое символическое название (идентификатор), в какой-то степени раскрывающее ее содержание. В структурированном программировании решение данной задачи всегда делается за один шаг, выполнение которого состоит в выборе одной из некоторого числа альтернатив. Если формулировка задачи была такова, что она могла быть решена применением одного базисного оператора алгола 60 (оператор присваивания или оператор процедуры), то шаг состоит в заключительном программировании, т. е. в сопоставлении названию задачи выполняющего ее оператора. В противном случае шаг состоит из структурирования задачи, т. е. из однократного разбиения ее на некоторое (малое) число других, более простых задач. Предполагается, что полнота знания о задаче позволяет программисту на данном шаге безошибочно решить, как структурируется его задача: на конкатенацию, на альтернативу или на итерацию. Конкатенация означает, что задача представляет собой последовательное решение двух задач: XI, а затем Х2. Эти две задачи образуют составной оператор или блок, если задача XI вырабатывает некоторую новую информацию, воспринимаемую затем
§ 4.2. СТРУКТУРИРОВАННОЕ ПРОГРАММИРОВАНИЕ 147 задачей Х2. В этом случае перед задачей XI появляется описательная часть, в которой описываются новые величины, локальные в данном блоке. При этом в голове у программиста происходит некоторая перестройка, которая заменяет сводное знание об f' Знание "X ι о задаче \ Задача А Ооьекты задачи А S''Знание*ч ^Знание^\ \ о задаче ) \ о задаче ) ; Задача Х1 * Задача XI конец -ты задачи А Рис. 4.1. Конкатенация. исходной задаче «расчлененными знаниями» о задачах XI и Х2 (см. рис. 4.1). Объекты исходной задачи либо полностью, либо частично становятся глобальными объектами задач XI и Х2. При выборе имен для локальных величин, связывающих XI и Х2, необходимо следить, чтобы не произошло коллизий между этими именами и именами глобальных величин. Альтернатива означает, что задача представляет собой проверку некоторого условия R и, в зависимости от его истинности или ложности, выполнения задачи XI или Х2 соответственно.Таким образом, условие R вместе с задачами XI и Х2 образует условный оператор алгола (см. рис. 4.2). Локальные величины при этом структурировании не возникают. Задача Х2 может отсутствовать, что приводит к конструкции условного оператора без иначе. Итерация.озпачает, что задача представляет собой цикл по некоторому параметру ί с условием повторения Я (это может быть либо условие типа нока, либо заголовок цикла типа арифметической прогрессии), в котором происходит циклическое выполнение задачи Х(0> образующей тело оператора цикла (рис. 4.3). Как видно, правила структурированного программирования очень просты. Их смысл в том, что они не позволяют при построении программы сделать слишком большого шага, при этом структурные ограничения предотвращают появление сложных информационных зависимостей и запутанных передач управления (как ,. м Локальные одъекты А. начало - Vyt vn 1 задач Ли/Ζ г Одъек>
148 ГЛ 4. РЕАЛИЗАЦИЯ видно, переходы по метке при таком подходе вообще не возникают). Не менее важным является постоянное «перетряхивание» / Знание \ \ о задаче } Задача А f Знание^\ ι о задаче ) И: если услодие-задачаR то г' Знание^ \ о задаче ) г онание \ ι о задаче ) задача Х1 иначе задачаХ2 Одьеты задача А Рис. 4.2. Альтернатива. Знание о \ада Задача А Одъекты задачи А А: начала Описание параметра i С / " Знаниё"\ г'"Знани1Г\ ι о задаче ) » о задаче ) ; йпя L-услодие-задача R цикл задача Хф Одьеты задачи А Рис. 4.3. Итерация. и «фильтрация» нашего знания об исходной задаче при его переносе на новые подзадачи. Кстати говоря, эта сопровождающая работа мысли стоит программисту больших усилий. Таким образом, структурирование не делает программирование проще, наоборот, оно даже становится еще более напряженным. Однако его систематический и дисциплинирующий характер вознаграждает программиста более достоверным и легче проверяемым результатом*
§ 4.2. СТРУКТУРИРОВАННОЕ ПРОГРАММИРОВАНИЕ 149 В качестве предварительной демонстрации структурированного программирования мы возьмем построение программы, пожалуй, наиболее традиционного примера алгоритма — нахождения наибольшего общего делителя двух Положительных целых чисел. Автор проведет эту демонстрацию в несколько подчеркнутой манере, обращая внимание читателя на широту диапазона умственных усилий программиста — от общей идеи алгоритма до скрупулезного обсуждения способа перестановки двух значений. Кроме то- то, мы введем и объясним определенный стиль записи процесса программирования, которого будем придерживаться. Процесс составления программы будет записываться по абзацам. Каждый абзац относится к одному акту структурирования программы и начинается символическим именем структурируемой задачи. Если способ структурирования задачи очевиден и не требует пояснений, то соответствующая конструкция (конкатенация, альтернатива или итерация) пишется вслед за именем задачи, отделяемая от него двоеточием. Получившаяся строка называется структурной формулой. Если считать имя задачи меткой, а используемые для краткости фигурные скобки служебными словами начало и конец, структурная формула становится конструкцией алгола. Для ссылок структурные формулы нумеруются. Номер, стоящий в косых скобках вслед за именем структурируемой задачи,—-это служебная ссылка на формулу, в которой эта задача появилась в качестве подзадачи. Наоборот, номер в косых скобках, стоящий вслед за именем только что появившейся подзадачи, — это служебная ссылка на структурную формулу, структурирующую данную подзадачу. Эти ссылки ставятся только в том случае, если формула, вводящая подзадачу, и формула, -ее структурирующая, не стоят подряд. 6 общем случае структурная формула будет предваряться некоторым содержательным рассуждением, отражающим наше знание о задаче. Для того чтобы не загромождать чрезмерно изложение, автор постарается быть лаконичным, полагая, что основы нашего знания закреплены предыдущей главой. Основная цель рассуждения — сделать очевидным выбор структурной формулы данной задачи. Само рассуждение будет начинаться словом прим, за ним будет стоять имя рассматриваемой задачи, за которым в косых скобках будет помещаться ссылка на формулу, в которой появилась задача, а также список глобальных величин, используемых по существу при решении задачи. В конце комментарий завершается словом итак, как бы представляющим структурную формулу вниманию читателя. В простых случаях при приближении к заключительному программированию мы будем иногда объединять неоколько структурирований в одну формулу.
150 ГЛ. 4. РЕАЛИЗАЦИЯ Нахождение наибольшего общего делителя прим Пусть χ и у — заданные натуральные числа, a z — их наибольший общий делитель. Мы будем строить программу как описание процедуры НОД, имеющей х> у и ζ своими формальными параметрами. Итак (1) ироц НОД (х, у, ζ); знач х, у; цел х, у, ζ; ТЕЛО НОД прим ТЕЛО НОД /х, у, ζ/. Задача решается сведением ее к простейшей. Пусть ОСТ (А, В) — это остаток от целого деления А на В. Если мы знаем, что ОСТ (ζ/, х) = 0, то тогда ζ = χ. Если же χ не делит г/, то тогда, как известно ИОД (х, у) = = НОД (ОСТ (у, х), х). Это соотношение позволяет нам редуцировать числа, вовлекаемые в рассмотрение, до тех пор пока, остаток не окажется равным нулю. Задача, тем самым, делится на последовательность двух: редукции и извлечения ответа из величины х. При этом используется процедура нахождения остатка. Итак (2) ТЕЛО НОД: { цел проц ОСТ (А, В); знач А, В; цел А, В; ТЕЛО ОСТ; РЕДУКЦИЯ/А/; ζ : =х} прим ТЕЛО ОСТ!А, В/ состоит из одного оператора присваивания, использующего целое деление. Итак (3) ТЕЛО ОСТ: ОСТ: = А — (А + В)хВ прим РЕДУКЦИЯ /х, у/. Очевидно, что редукция носит повторный характер. На каждом шаге редукции χ и у заменяются соответственно ОСТ(у, х) и х, а повторение контролируется значением величины и = ОСТ (х, у). Итак (4) РЕДУКЦИЯ: {цел и; для и: = ОСТ (у, х) пока и Φ 0 цикл ЗАМЕНА} (5) ЗАМЕНА: {у : = χ; χ : = и} Для того чтобы собрать программу из структурных формул, нужно произвести систематические подстановки структурной формулы для' задачи в другую структурную формулу, в которой эта задача упоминается в качестве подзадачи. Имена задач, остающиеся в программе в качестве меток, не обязательны и могут быть выброшены, так как структурированная программа не содержит операторов перехода. Некоторые метки в собранной программе оставлять все же полезно для того, чтобы сохранить в ней смысловые опорные точки. Ниже показана результирующая программа нахождения наибольшего общего делителя. проц НОД (х, у, ζ); знач х, у; цел х, у, ζ; начало цел проц ОСТ (А, В); знач А, В; цел А, В\ ОСТ : = А - (Α -τ- Β) Χ В;
§ 4.3. ОБЩАЯ ОРГАНИЗАЦИЯ ЭКОНОМИИ ПАМЯТИ £51 РЕДУКЦИЯ: начало цел и; для и : = ОСТ (х, у) пока иФО цикл начало у : = х\ χ : = и конец; конец: ПОЛУЧЕНИЕ: ζ : = χ конец § 4.3. Общая организация экономии памяти Весь последний текст главы будет выглядеть наподобие только что приведенного демонстрационного примера. Возможно, что читать его будет не трудно, но очень скучно. Чтение можно будет сделать более медленным, но и гораздо более интересным, если попытаться самому структурировать программу экономии памяти, используя текст главы для контроля. Читатель может быть уверен, что это будет соревнование с автором (при условии, конечно, полноценного знания предыдущих глав и некоторого навыка в алголе) почти-на равных, так как для автора написание этой главы было его первым упражнением в структурированном программировании, а сама программа приведена именно в том виде, в каком она получалась (не считая, естественно, переписываний, вызванных замеченными ошибками). Экономия памяти в операторной схеме прим Мы начинаем с уточнения объектов задачи. В соответствии со сказанным во вступлении к этой главе мы будем представлять элементарные абстрактные объекты, главным образом, натуральными числами, их множества— отрезками натурального ряда, а подмножества — логическими шкалами. Для того чтобы задать множество операторов, нам достаточно указать цел η — число операторов. Управляющий граф мы будем изображать, матрицей смежности цел массив СИ : пу 1 : п], в которой C[i, j] равен 1, если/-й оператор является преемником i-το оператора, и 0 в противном случае. Такое представление удобно для построения транзитивных замыканий, так как i-я строка матрицы С—это множество преемников оператора i, а /-й столбец — множество предшественников оператора /. Множества аргументов'и результатов в сумме образуют множество полюсов. Поскольку нам приходится работать, как вообще с полюсами, так и, в частности, с аргументами и результатами, нам будет удобнее рассматривать множество полюсов как отрезок натурального ряда от 1 до ρ + g, где цел ρ — число аргументов, а цел q — число результатов. В этом случае ί-й результат изображается числом ρ + i. Распределение полюсов при этом естественно изображается вектором цел массив Π1:ρ + ϊ1,
152 ГЛ. 4. РЕАЛИЗАЦИЯ где V[j] — оператор, сопоставленный /-му полюсу. Вектор цел массив LH : ρ + q] задаст распределение памяти, если считать, что L[i] — это величина, сопоставленная ί-му полюсу. Для заданной таким образом операторной схемы мы будем искать цел массив Li [1 : ρ + #1 — новое, по возможности экономное распределение памяти. Программу Экономии Памяти в Операторной Схеме мы будем строить в виде описания процедуры ЭПОС с перечисленными формальными параметрами. Итак (1) проц ЭПОС (п, C,p,q, V, L, Li); знач η, С,ру q, V, L; цел η, ρ, q; цел массивы С, V, L, Li; ТЕЛО ЭПОС прим ТЕЛО ЭПОС/п, С, р, q, V, L, Li/. Узловым моментом экономии памяти является построение информационного графа, а более точно — его областей действия. Фактически результатом построения областей действия будет цел I — число областей действия и каноническое распределение памяти цел массив LK[1 : ρ -\- q], в котором всем полюсам, относящимся к i-и области действия, будет сопоставлена величина i. Экономия памяти будет производиться на основе канонического распределения. Итак (2) ТЕЛО ЭПОС: {цел Z; цел массив LK [1 : ρ + q\; КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ΠΙ; ЭКОНОМИЯ ПАМЯТИ} прим ЭКОНОМИЯ ПАМЯТИ In, С, р, q, V, I, LK, Li/. Мы хотим прежде всего структурировать нашу программу выделением крупных разделов, которые образуют в свою очередь содержание параграфов данной главы. ЭКОНОМИЯ ПАМЯТИ естественно расчленяется на получение графа несовместимости и на его последующую раскраску, которая и задаст нужное распределение памяти. Аналогично графу переходов мы зададим граф несовместимости его матрицей смежности цел массив UH : Z, 1 : Z], в которой U[i, /] = 1, если i-я и /-я области несовместимы, и U[i, /] = 0 в противном случае. Очевидно, что матрица U — симметрична. Итак (3) ЭКОНОМИЯ ПАМЯТИ: {цел массив UH : Z, 1 : Z]; ПОЛУЧЕНИЕ ГРАФА НЕСОВМЕСТИМОСТИ /49/; РАСКРАСКА И ОКОНЧАТЕЛЬНОЕ РАСПРЕДЕЛЕНИЕ) прим РАСКРАСКА И ОКОНЧАТЕЛЬНОЕ РАСПРЕДЕЛЕНИЕ /р, q, Z, LK, U, L1/. Структурирование задачи подсказывается ее названием. Раскраску вершин графа U с учетом уже имеющихся примеров представления отображений проще всего представить вектором цел массив Q[i : Ζ], где Q[i] — краска, сопоставленная i-й вершине графа несовместимости,.
§ 4.4. КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ПАМЯТИ 153 При этом предполагается, что множество использованных красок, как и ранее, представлено отрезком натурального ряда. Итак (4) РАСКРАСКА И ОКОНЧАТЕЛЬНОЕ РАСПРЕДЕЛЕНИЕ: {цел массив Q[l : I); PACKPACKAI75/; ОКОНЧАТЕЛЬНОЕ РАСПРЕДЕЛЕНИЕ} прим ОКОНЧАТЕЛЬНОЕ РАСПРЕДЕЛЕНИЕ /р, qy LK, Q, LI// Мы доведем до конца заключительную часть программы, чтобы потом сконцентрировать внимание на главных подзадачах. Для получения экономного окончательного распределения памяти нам нужно для каждого полюса найти краску, сопоставленную его области действия, и сопоставить ее самому полюсу. Итак (5) ОКОНЧАТЕЛЬНОЕ РАСПРЕДЕЛЕНИЕ: {цел /; для/ : = 1 таг 1 до ρ + q цикл СВОЯ КРАСКА J-МУ ПОЛЮСУ} прим СВОЯ КРАСКА J-МУ ПОЛЮСУ //, LK, <?, L1/. Нам нужно определить значение Li[j]. LK[j] дает нам номер области действия, к которой относится /-й полюс. Так как Q[i] — это краска, сопоставленная i-й области действия, то искомая краска равна QlLKlj]]. Итак (6) СВОЯ КРАСКА J-МУ ПОЛЮСУ: L\[j\ : = Q[LK[j]] Итак, мы выделили три крупные подзадачи, которыми и будеы заниматься до конца главы. Это КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ, ПОЛУЧЕНИЕ ГРАФА НЕСОВМЕСТИМОСТИ и РАСКРАСКА. § 4.4. Каноническое распределение памяти прим КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ /(2)л, С, р, g, Vf L, Ζ, LK/ начинается с того, что согласно § 3.1 каждый полюс считается принадлежащим «своей собственной» компоненте связности информационного графа. Другими словами, происходит максимальная расклейка распределения памяти, задающая начальное значение вектора LK. После этого производится непосредственное построение областей действия. Итак <7) КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ: {РАСКЛЕЙКА ПОЛЮСОВ; ПОСТРОЕНИЕ ОБЛАСТЕЙ ДЕЙСТВИЯ /9/} лрим РАСКЛЕЙКА ПОЛЮСОВ /р, q, LK/ очевидно решается итерацией сопоставления ΐ-му полюсу (i = 1, . · ., ρ + q) величины i. Итак
154 ГЛ. 4. РЕАЛИЗАЦИЯ (8) РАСКЛЕЙКА ПОЛЮСОВ: {цел ц для i: = 1 шаг 1 до ρ + q цикл LKli] : = i} лрим ПОСТРОЕНИЕ ОБЛАСТЕЙ ДЕЙСТВИЯ /(7) п, С, р, qr V, L, I, LKI должно построить не только каноническое распределение памяти LK, но и подсчитать число областей: действия /. Итак (9) ПОСТРОЕНИЕ ОБЛАСТЕЙ ДЕЙСТВИЯ: {НАХОЖДЕНИЕ LK/ill; ПОДСЧЕТ ЧИСЛА ОБЛАСТЕЙ} прим ПОДСЧЕТ ЧИСЛА ОБЛАСТЕЙ ILK, II. По правилу слияния текущих областей действия мы всегда оставляем в схеме величину с меньшим номером. Это позволяет нам определить число областей взятием максимального элемента вектора LK* Итак (10) ПОДСЧЕТ ЧИСЛА ОБЛАСТЕЙ: {I: = 0; {цел i; для ί: = 1 шаг 1 до ρ + qцикл если LKli] > Ιτο Ι: = LK[i]}} срим НАХОЖДЕНИЕ LK/(9) η, С, ρ, q, V, L, LKI согласно § 3.1 есть итерация построения ограниченного транзитивного образа оператора для каждого результата схемы, в процессе построения которого будет в нужных случаях происходить слияние текущих компонент связности. Итак (И) НАХОЖДЕНИЕ LK: {цел i; для i : = 1 шаг 1 до q цикл ТРАНЗАМ 1-ГО РЕЗУЛЬТАТА} прим ТРАНЗАМ 1-ГО РЕЗУЛЬТАТА In, С, р, q, V, L, LK, if. Построение ограниченного транзитивного образа требует перед выполнением основного итерационного цикла движения по дугам графа определенной подготовительной работы. Нам надо будет задать начальные значения стартового и пополняемого множеств S и Т, а также построить ограничивающее множество R. Для слияния текущих областей действия нам нужно по ходу дела фиксировать моменты достижения операторов, воспринимающих величину, сопоставленную г-му результату. Эти операторы образуют «аргументное» множество л. Все эти множества мы представим в виде логических шкал длины п. Необходимость ввести эти множества очевидна и лежит, так сказать, на поверхности. Предстоящий шаг структурирования задачи дзет нам, однако, хороший материал для понимания того, что безошибочное структурирование и своевременное введение новых объектов требует поистине полноты знания задачи и четкого представления, как будет протекать работа во внутренних слоях программы. В данном случае речь идет о механизме слияния текущих компонент связности при попадании во время построения транзитивного замыкания на оператор из аргументного мно-
§ 4.4. КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ПАМЯТИ 155 жества А. После того как мы обнаружим, что в Τ попадает некоторый оператор/,принадлежащий А, мы должны найти аргумент этого оператора, которому сопоставлена величина L[p+i],n объединить текущую компоненту связности этого аргумента с компонентой связности i-ro результата. Вспомним (§ 2.2), что в общем случае таких аргументов у оператора может быть несколько, хотя в исходной схеме такие случаи следует считать весьма редкими. Поскольку величина L[p + -f- i] и оператор /, воспринимающий L[i], нам даны, поиск аргументов, т. е. такихfe, чтобы V[k] = /, a L[k] = L[p -f- ί], может быть осуществлен просмотром аргументной части вектора L. Если бы аргументам каждого оператора сопоставлялись всегда разные величины, то тогда для аргументного множества А можно было бы иметь второй вектор цел массив а[1 : п], в котором α[ί\ было бы равно аргументу к оператора /, для которого L[k] = Lip + i]. Такой вектор можно построить при подготовке. Это тем более соблазнительно, что такая ситуация будет встречаться наиболее часто. Тем не менее мы не можем игнорировать общий случай, когда оператор имеет сколько угодно (вплоть до р) аргументов с одной и гой же величиной. Мы, однако, имеем возможность путем некоторых ухищрений объединить выгодность формирования списка аргументов а с общностью алгоритма. Для этого мы будем в аргументном множестве А различать операторы с однократным восприятием величины L[p + i] и с многократным. Это будет делаться так, что при отнесении оператора к аргументному множеству единица в нужную компоненту вектора А будет не ставиться, а добавляться. Это произойдет столько раз, сколько раз величина L[p + i] оказалась со1 поставленной аргументам этого оператора. Если оператор воспринимает величину многократно, в список аргументов α для определенности будет помещаться первый по порядку аргумент. Остальные же аргументы будут искаться в векторе L. Сигналом для этого будет признак принадлежности оператора множеству А, равный не единице, а больному числу. Итак (12) ТРАНЗАМ 1-ГО РЕЗУЛЬТАТА: {цел массивы 5, 7\ Я, Л, all: и]; ПОДГОТОВКА; ДВИЖЕНИЕ ВДОЛЬ ДУГ /22/} прим ПОДГОТОВКА In, ρ, q, V, L, i, S, T, R, A, al. Осмыслим способы задания множеств S, Г, Я, А, а. Множество S содержит единственный оператор V[p + i]. Множество Τ пусто. Множества R и А — это своего рода «линии уровня», т. е. множества тех операторов, которые в распределении полюсов сопоставлены полюсам, имеющим своей величиной
156 ГЛ. 4. РЕАЛИЗАЦИЯ Lip + i]. Можно вообразить способ их получения. Двигаясь вдоль вектора L, мы будем узнавать среди его компонент нужное значение Lip -+- i] и но номеру компоненты / извлекать нужный оператор Vlj], помечая единицей в векторе R компоненту с номером Vlj] и добавляя единицу к аналогичной компоненте вектора А. Остальные компоненты векторов А и R должны быть нулевыми. Таким образом, прежде чем производить содержательное формирование множеств S, R, А и а, нам их все (а также, естественно, и Т) надо «обнулить». Итак (13) ПОДГОТОВКА: {ИНИЦИАЛИЗАЦИЯ; ЗАПОЛНЕНИЕ /15/} (14) ИНИЦИАЛИЗАЦИЯ: {цел /; для /: = 1 шаг 1 до η цикл Tlj] : = Slj] : = Rlj] : = А [/] : = alj] : = 0} (15) ЗАПОЛНЕНИЕ /13/: {S[Vli+ p]]: = U ЗАПОЛНЕНИЕ ОСТАЛЬНОГО} (16) ЗАПОЛНЕНИЕ ОСТАЛЬНОГО: {ЗАПОЛНЕНИЕ R; ЗАПОЛНЕНИЕ А /19/} прим ЗАПОЛНЕНИЕ R In, p, g, F, L, г, RL В соответствии со сказанным в (13)ч^мь1 будем двигаться вдоль вектора L (более точно, вдоль той его части, которая относится к результатам: L[p + 1: ρ + q] и, пользуясь вектором V, на'ходить нужный оператор. Итак (17) ЗАПОЛНЕНИЕ R: {цел /; для /: = 1 шаг 1 до q цикл ПРОВЕРКА ОЧЕРЕДНОГО РЕЗУЛЬТАТА} (18) ПРОВЕРКА ОЧЕРЕДНОГО РЕЗУЛЬТАТА: ccmiLlp +/]= Lip + i] то RlVlp +j]]:= i прим ЗАПОЛНЕНИЕ А/(16) тг, ρ, F, L, i, А, а/ делается аналогично заполнению R с тем отличием, что мы движемся вдоль аргументной части вектора L, а также заполняем указанным в (12) способом множество аргументных полюсов а. Итак (19) ЗАПОЛНЕНИЕ А: {цел /; для /:= 1 таг 1 до ρ цикл если L[j] = Lip -h i] το ЗАГРУЗКА КОМПОНЕНТЫ} прим ЗАГРУЗКА КОМПОНЕНТЫ IV, Л, а, /7 делается по разному, в зависимости от того, в первый или не в первый раз обнаружен нужный аргумент. Если оператор V[j] уже содержится во множестве А, то кратность аргумента увеличивается на единицу. Если же оператор Vlj] еще не попал в Ау то тогда он не только отмечается в нем, но и соответствующий аргумент заносится в а. Итак
§ 4.4. КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ПАМЯТИ 157 (20) ЗАГРУЗКА КОМПОНЕНТЫ: если A [Ft/]] = 0 то ЗАНЕСЕНИЕ В А иначе A[V[j]]: = A[V[j]\ + 1 (21) ЗАНЕСЕНИЕ В A: {a[V[j]]i = /: A[V[j]]: = 1} прим ДВИЖЕНИЕ ВДОЛЬ ДУЩ12) п, С, LK, i, S, Г, Д, AL В соответствии с правилами построения транзитивного замыкания (§ 3.1) стимулом к продвижению вдоль дуг является непустота стартового множества. Условие непустоты множества, изображаемого логической шкалой некоторой длины, мы оформим в виде логической процедуры-функции, так как такие проверки у нас будут встречаться неоднократно. После построения всей программы мы определим надлежащий уровень локализации этой процедуры с тем, чтобы ее описание было бы доступно всем вызовам. Итак (22) ДВИЖЕНИЕ ВДОЛЬ ДУГ: {цел /; /: = 0; для /: = / + 1 пока НЩУСТО (S, п) цикл ДВИЖЕНИЕ И СОГЛАСОВАНИЕ /28/} прим НЕПУСТО /S, п/. В рамках структурированного программирования поиск первой отличной от нуля компоненты в логической шкале требует небольших ухищрений, связанных с отсутствием меток (свойство структурированного программирования). Для этого движение вдоль шкалы мы запрограммируем циклом, в процедуру введем локальную величину, запоминающую факт обнаружения ненулевой компоненты, а после выхода из цикла в зависимости от значения величины, будем определять результат процедуры. Итак (23) лог проц НЕПУСТО (А, т); знач т; цел т; цел массив А[1 : т]; ТЕЛО НЕПУСТО (24) ТЕЛО НЕПУСТО /А, ml: {лог р; р: = истина; ПРОВЕРКА } (25) ПРОВЕРКА: {ПРОСМОТР А; ПРОБА Ρ /27/} (26) ПРОСМОТР А: {цел i; j:= 0; для* i : = i+ί пока i < η&μ цикл р:· = A [i] ' — 0} (27) ПРОБА Ρ /25/: НЕПУСТО: ^~]р прим ДВИЖЕНИЕ И СОГЛАСОВАНИЕ/(22) п< С, LK, ί, 5, ТТ R, AL Вспомним алгоритм построения областей действия в § 3.1. Разберемся более подробно с шагом индукции. По стартовому множеству S мы находим Г(5), которое в нашем представлении будет логической суммой (IV 1 = 0 V I — = 1\/0=1;0\/0 = 0) всех строк матрицы С с номерами, соответствующими ненулевым компонентам вектора S. Для накопления Г(5) нам потребуется локальный вектор цел массив ГЦ : п], которому должно быть задано начальное пустое значение. После получения Г мы прибавляем его к
158 ГЛ. 4. РЕАЛИЗАЦИЯ пополняемому множеству Г и по ходу дела проверяем, не попадает ли очередной элемент Г в аргументное множество А. При таком попадании необходимо будет проверить с помощью вектора LK, отнесены ли i-й результат и соответствующий аргумент оператора из Л к одной и той же текущей компоненте, сливая их в одну, если это не так. В этом же цикле движения вдоль вектора Г мы можем извлечь из него элементы следующего стартового множества: элемент из Г входит в следующее S только в том случае, если он не входит в предыдущее Г и не вырабатывает L[p -h i], т. е. не входит в Д. Итак <28) ДВИЖЕНИЕ И СОГЛАСОВАНИЕ: {цел массив ГЦ : п]; НАХОЖДЕНИЕ Γϊ; ИСПОЛЬЗОВАНИЕ ΓΞ /35/} <29) НАХОЖДЕНИЕ rS In, С, S, ΓΙ: {ФОРМИРОВАНИЕ ΓΞ; СУММИРОВАНИЕ ΓΞ /31/} <30) ФОРМИРОВАНИЕ ΓΞ: {цел i; для i: = 1 шаг 1 до η цикл ЛП: = 0} (31) СУММИРОВАНИЕ ΓΞ /(29) η, С, S, ΓΙ: {цел i; для i: = 1 mar 1 до η цикл ПРОВЕРКА SI} (32) ПРОВЕРКА 57: если S[i] φ 0 то ДОБАВЛЕНИЕ CI (33) ДОБАВЛЕНИЕ CI In, С, Г, И: {цел /; для /: = 1 шаг 1 до η цикл ДОБАВЛЕНИЕ СП) (34) ДОБАВЛЕНИЕ СП: если СИ, Л = 1 то Л/1: = 1 прим ИСПОЛЬЗОВАНИЕ rS I (28) п, LK, i, S, Τ, R, ΑΙ — это, прежде всего, цикл поочередного использования его элементов. Итак (35) ИСПОЛЬЗОВАНИЕ ΓΞ: {цел /; для /: - 1 шаг 1 до η цикл РАБОТА С ОЧЕРЕДНЫМ ЭЛЕМЕНТОМ} (33) РАБОТА С ОЧЕРЕДНЫМ ЭЛЕМЕНТОМ: {ПЕРЕСЧЕТ СТАРТОВОГО; ДОБАВЛЕНИЕ К ПОПОЛНЯЕМОМУ /38/} прим ПЕРЕСЧЕТ СТАРТОВОГО In, S, Τ, R, Г, jl. Согласно § 3.1 оператор не входит в S, если он не входит в Г. Если же оператор входит в Г, то исключается случай, когда он принадлежит Τ или R. Итак (37) ПЕРЕСЧЕТ СТАРТОВОГО: если Л/1 = 0 то £[/]: = О иначе если T[j] φ О V Д1Л Φ Ото Slj]: = 0 иначе S[j]: = 1 прим ДОБАВЛЕНИЕ К ПОПОЛНЯЕМОМУ /(36), п, р, У, L, i, Τ, А, а, Ц прежде всего зависит от того, входит ли оператор j в Г. Итак
§ 4.4. КАНОНИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ПАМЯТИ 159 (38) ДОБАВЛЕНИЕ К ПОПОЛНЯЕМОМУ: если Л/] «И8 0 то РАБОТА С ЭЛЕМЕНТОМ Г (39) РАБОТА С ЭЛЕМЕНТОМ Г: {Л/]: = 1; ВОЗМОЖНОЕ СОГЛАСОВАНИЕ) прим ВОЗМОЖНОЕ СОГЛАСОВАНИЕ In, ρ, V, L, i, Г, Л, α, // начинается с проверки принадлежности оператора / аргументному множеству. Итак (40) ВОЗМОЖНОЕ СОГЛАСОВАНИЕ: если Л[/]=И=0 то С0Г- прим СОГЛАСОВАНИЕ /р, F, L, г, Л, а, //. В силу сказанного в (12) СОГЛАСОВАНИЕ проводится в два приема: для первого аргумента оператора / и для возможных остальных. Первый аргумент извлекается из множества аргументных полюсов а, а остальные, если они есть, ищутся в аргументной части множества L. Сказанное означает, что слияние текущих компонент связности i-ro результата и найденного аргумента будет выполняться в двух местах программы, в связи с чем слияние целесообразно программировать как процедуру с двумя формальными параметрами: результат г и аргумент а. Итак (41) СОГЛАСОВАНИЕ: {проц СЛИЯНИЕ (г, а); знач г, а; цел г," а; ТЕЛО СЛИЯНИЯ; ПЕРВЫЙ АРГУМЕНТ /46/; ОСТАЛЬНЫЕ АРГУМЕНТЫ /47/} прим ТЕЛО СЛИЯНИЯ /р, g, LK, г, а/. Если г и а относятся к одной компоненте, т. е. если LK [р -\- г] = LK[a], то LK остается без изменений. В противном случае происходит выравнивание значений: все вхождения MAX(LK[p + г], LK[a\) в вектор LK заменяются на MIN(LK[p + г]% Ζ,/Πα]). Итак (42) ТЕЛО СЛИЯНИЯ: {если LKlp + г] =£ LK[a ] то ВЫРАВНИВАНИЕ} (43) ВЫРАВНИВАНИЕ: {цел ш, max; НАХОЖДЕНИЕ MIN МАХ; ЗАМЕНА МАХ НА MIN) (44) НАХОЖДЕНИЕ MIN MAX: если LKlp + r]< LKla] то {min: = LKlp + Η; лт#: = Ζ/7Πα]} иначе {mm: = LKla]; max: = ΖΛΠρ + г]} (45) ЗЛМЯЯЛ AL4X НА MIN: {цел ί; для i: = 1 шаг 1 до ρ + q цикл если LK[i] = max то LK[i]: = ш} (46) ПЕРВЫЙ АРГУМЕНТ /41/: СЛИЯНИЕ (α[/ϊ, ί) (47) ОСТАЛЬНЫЕ АРГУМЕНТЫ /41/: если Л [/] > 1 то ЯРО- СМОТР АРГУМЕНТОВ
160 ГЛ. 4. РЕАЛИЗАЦИЯ прим ПРОСМОТР АРГУМЕНТОВ /р, V, L, *, Ау а, // состоит в последовательном просмотре аргументной части множества полюсов. Так как α [у] хранит первый нужный аргумент, просмотр естественно начинать с номера alj] + 1. При обнаружении аргумента к, для которого L[k\ = L[ р + i], дополнительно проверяется, не относится ли он к рассматриваемому оператору /. В этом случае к вместе с i отправляется на процедуру слияния их текущих компонент связности. Итак <48) ПРОСМОТР АРГУМЕНТОВ: {цел fe; для к: = a[j] + 1 шаг 1 до ρ цикл если L[k] = Lip + i]&V[k] = j то СЛИЯНИЕ (к, i)} § 4.5. Получение графа несовместимости ярим ПОЛУЧЕНИЕ ГРАФА НЕСОВМЕСТИМОСТИ /(3) л, С, р, q, V, I, LK, U/. Согласно § 3.2 заключительным материалом для прямого определения несовместимости двух областей действия d и d! являются множества R{d), R(d'), T{d) и T{d'), где R{d) — множество операторов, вырабатывающих величину х, сопоставленную области d, a T(d) — множество транзитных операторов всех маршрутов всех информационных пэр, реализуемых величиной χ (напомним, что сейчас мы имеем дело с каноническим распределением памяти). T(d) в свою очередь получается пересечением двух множеств Ε (d) и L (d)y где Ε (d) — транзитивный образ множества R (d), ограниченный им же, a L (d) —транзитивный прообраз множества A(d) операторов, воспринимающих величину х, при этом сильно ограниченный множеством R(d). Напомнив эти факты, мы заодно перечислили основные внутренние объекты, возникающие при построении графа несовместимости. Поскольку отношение несовместимости должно быть вычислено попарно для всех величии, правда, с учетом симметрии, нам перед вычислением матрицы U нужно иметь R и Τ для всех I величин. Поскольку каждое множество — эго шкала длины п, мы приходим к описанию этих множеств в виде матриц цел массив R, Τ И: I, 1: тг], а также получаем естественное структурирование задачи. Итак (49) ПОЛУЧЕНИЕ ГРАФА НЕСОВМЕСТИМОСТИ: {цел массив Д, Τ Ιί: Ζ, 1: л]; ВЫЧИСЛЕНИЕ RmT /55/; ВЫЧИСЛЕНИЕ Щ прим ВЫЧИСЛЕНИЕ U In, I, U, Д, Т/ аналогично вычислению суммы трех произведений матриц: U = R' X R -+■ R' X Χ Τ + Τ' Χ R, где шгрих означает транспонирование
§ 4.5. ПОЛУЧЕНИЕ ГРАФА НЕСОВМЕСТИМОСТИ 161 матрицы. Напомним, что элемент [i, j] матрицы произведения матрицы А на матрицу В равен скалярному произведению i-ж строки матрицы А на /-й столбец матрицы В, т. е. сумме пожарных произведений их компонент. Так как нам нужно вычислить сумму трех произведений, в цикле суммирования мы можем складывать сразу три попарных произведения компонент нужных комбинаций строк и столбцов матриц R и Г. Наконец, хотя нам нужна матрица U, состоящая из нулей и единиц, мы можем заменить логические умножения и сложения арифметическими, нормализовав, впоследствии вычисленный элемент матрицы U, заменяя любое его ненулевое значение на единицу. Ко всему этому напомним, что мы будем вычислять фактически только «верхний треугольник» матрицы U, засылая вычисленный элемент U как в позицию U, /], так и в позицию [/, i], и без вычислений полагая диагональные элементы матриц равными нулю. Итак (50) ВЫЧИСЛЕНИЕ U: {ДИАГОНАЛЬНЫЕ ЭЛЕМЕНТЫ; ОСТАЛЬНЫЕ ЭЛЕМЕНТЫ /52/} <51) ДИАГОНАЛЬНЫЕ ЭЛЕМЕНТЫ: {цел i; для i: = 1 шаг 1 до Ζ цикл U[i, i]: = 0} {52) ОСТАЛЬНЫЕ ^ЭЛЕМЕНТЫ: {цел i; для i: = 1 шаг 1 до Ζ —- 1 цикл {цел /; для /: = i -γ- 1 шаг Г до Ζ цикл ВЫЧИСЛЕНИЕ И ПОСТАНОВКА }} {53) ВЫЧИСЛЕНИЕ И ПОСТАНОВКА: {цели; ВЫЧИСЛЕНИЕ ЭЛЕМЕНТА; Uli, /]: = U[j, i]: = если и = 0 то 0 иначе 1} {54) ВЫЧИСЛЕНИЕ. ЭЛЕМЕНТА: {и: = 0; {цел к; для к: = 1 шаг 1 до л цикл и: — и + R[i, к] χ R[j, к) + ВЦ, к] X Т\]\ к]+ ТЦ, к] χ R[j, к]}} ярим ВЫЧИСЛЕНИЕ ИИ Τ /(49) η, С, ρ, q, V, I, LK, Я, ΤΙ. Это вычисление мы будем вести по очереди для всех величин канонического распределения памяти. Итак (55) ВЫЧИСЛЕНИЕ R И Т: {цел i; для i: = 1 шаг 1 до Ζ цикл ОБРАБОТКА ОЧЕРЕДНОЙ ОБЛАСТИ) прим ОБРАБОТКА ОЧЕРЕДНОЙ ОБЛАСТИ In, С, р, g, F, LA', Л, Г, ι/. Следуя комментарию к (49), получение R(d) предшествует получению T(d). Итак (56) ОБРАБОТКА ОЧЕРЕДНОЙ ОБЛАСТИ: {ПОЛУЧЕНИЕ R; ПОЛУЧЕНИЕ Τ /60/} прим ПОЛУЧЕНИЕ R /n, р, q, V, LK, R, Ц представляет собой просмотр результатной части распределения памяти LK. При обнаружении в (р + /)-й позиции величины i направ-
162 ГЛ. 4. РЕАЛИЗАЦИЯ ляется единица в V[p + /]-ю компоненту i-й строки матрицы R. Перед просмотром i-я строка «обнуляется». Итак (57) ПОЛУЧЕНИЕ R: {ОБНУЛЕНИЕ; ПРОСМОТР РЕЗУЛЬТАТОВ /59/} (58) ОБНУЛЕНИЕ /п, R, Ц: {цел /; для /: = 1 шаг 1 до η цикл Я[£, /]: = 0}· (59) ПРОСМОТР РЕЗУЛЬТАТОВ /(57) р, ?f V, LK, R, Ц: {цел /"; для /: — 1 шаг 1 до q цикл если LK[p -\- j] = i то Rlir Vlp +]]]: = 1} прим ПОЛУЧЕНИЕ Τ /(56).л, С, р, V, L£, Д, Г, Ц требует вы- числения множеств Ε и L, которые, пересекаясь, дадут множество Г. Итак (60) ПОЛУЧЕНИЕ Т: {цел массив Е, L[i: η]; ВЫЧИСЛЕНИЕ Ε И L /62/; ПЕРЕСЕЧЕНИЕ} (61) ПЕРЕСЕЧЕНИЕ In, Τ, £ £,£/: {цел /; для /: = 1 шаг 1 до гс. цикл Г[£, /I: = E[j] X Д/1} (62) ВЫЧИСЛЕНИЕ Ε И L /60/: {ВЫЧИСЛЕНИЕ Е; ВЫЧИСЛЕНИЕ L /69/} прим ВЫЧИСЛЕНИЕ Ε In, С, R, i, £V становится стандартной: задачей нахождения транзитивного ограниченного образа. Нам необходимо только ввести стартовое множество S с его начальным значением, равным R, и задать начальное пустое- значение пополняемого множества Е. Итак (63) ВЫЧИСЛЕНИЕ Е: {цел массив 5[1: п\; ИНИЦИАЛИЗАЦИЯ; ДВИЖЕНИЕ ПО ДУГАМ /65/} (64) ИНИЦИАЛИЗАЦИЯ In, R, i, S, El: {цел /; для /: = 1 шар 1 до и цикл {Sljh = R[i,jY, E[j]: = 0}} прим ДВИЖЕНИЕ ПО ДУГАМ /(63) п, С, Я, i, £, 5/ аналогична шагу (22) при построении канонического распределения памяти. Итак (65) ДВИЖЕНИЕ ПО ДУГАМ: {цел /; ;: = 0; для ;: =7 + 1 пока НЕПУСТО (S, п) цикл ДВИЖЕНИЕ} (66) ДВИЖЕНИЕ In, С, R, i, Ε, 57: {цел массив ГЦ: п]; НАХОЖДЕНИЕ Г; ИСПОЛЬЗОВАНИЕ Г/68/} прим НАХОЖДЕНИЕ Г/п, С, S, П. В качестве демонстрации- принципа экономии мышления мы перепишем в собранном виде формулы (29—34), решающие такую же задачу. Итак (67) НАХОЖДЕНИЕ Г: {{цел i; для i: = 1 шаг 1 до η цикл ГШ: = 0}; {цел i; для i: = 1 шаг 1 до η цикл если S[i] ^ О
§ 4.5. ПОЛУЧЕНИЕ ГРАФА НЕСОВМЕСТИМОСТИ 163 то {цел /; для /': = 1 шаг 1 до η цикл если C[i, /] = 11 то П/]: = 1>» ярим ИСПОЛЬЗОВАНИЕ Г /(66) η, R, ί, Ε, S, ΓΙ производится аналогично (35—39), за исключением того, что согласование отсутствует. Итак <68) ИСПОЛЬЗОВАНИЕ Г: {цел /; для /: = 1 шаг 1 до η цикл {ПЕРЕСЧЕТ СТАРТОВОГО: если ГЦ] --= О то 5[/]: =0 иначе если Е[]]фО\/ R[i,j] фОто 51/]: = 0 иначе 51/]: = 1; ДОБАВЛЕНИЕ К ПОПОЛНЯЕМОМУ: если ГЦ] φ О то E[j]: = 1}} прим ВЫЧИСЛЕНИЕ L /(62) п, С, р, К, LK, Λ, г, LI является задачей вычисления сильно ограниченного транзитивного прообраза. В качестве начального значения стартового множества берется множество А аргументов, которым в LK со- ι поставлена величина i. Начальное значение пополняемого множества L — пустое. Сильно ограничивающим множеством является i-я строка матрицы R. Итак <69) ВЫЧИСЛЕНИЕ L: {цел массив АН: п]; {{цел ί; для i: = 1 шаг 1 до η цикл A[i\: = L[i\: = 0}; НАХОЖДЕНИЕ А}; ДВИЖЕНИЕ НАВСТРЕЧУ ДУГАМ /71/} прим НАХОЖДЕНИЕ А 1р, V, LK, i, AI производится движением'вдоль аргументной части распределения памяти LK[i: ρ]. Обнаруживая в /-й компоненте величину ί, мы ставим единицу в Fl/I-ю компоненту множества Л. Итак {70) НАХОЖДЕНИЕ А: {цел /; для /: = 1 mar 1 до ρ цикл если LK[j] = i то AlVlj]]: = 1} 171) ДВИЖЕНИЕ НАВСТРЕЧУ ДУГАМ /(69) n,C,R,i,L, AI: {цел /; j: = 0; для /: = / + 1 пока НЕПУСТО (Л, п) цикл ПРОДВИЖЕНИЕ) (72) ПРОДВИЖЕНИЕ In, С, R, г, L, Л/: {цел массив Γ[ί: η]; ВЫЧИСЛЕНИЕ Г; ПРИМЕНЕНИЕ Г /74/} ярим ВЫЧИСЛЕНИЕ Г In, С, А, /7. При его вычислении надо помнить, что от элементов стартового множества мы переходим к его предшественникам, образующим столбцы матрицы С. Итак (73) ВЫЧИСЛЕНИЕ Г: {{цел i; для i: = 1 шаг 1 до η цикл Γ[ί]:= 0}; {цел i; для i: = 1 шаг 1 до η цикл если Α[ί] Φ 0 то {цел /; для /: = 1 шаг 1 до η цикл если C[j, i] = 1 то Д/]: = 1}}} прим ПРИМЕНЕНИЕ Г /(72) гс, Л, i, L, А, П делается так же, как и в (68), но при добавлении к пополняемому нам можно
164 ГЛ. 4. РЕАЛИЗАЦИЯ' добавлять только такой элемент из Г, который не принадлежит ограничивающему множеству. Итак (74) ПРИМЕНЕНИЕ Г: {цел /; для ;: = 1 шаг 1 до η цикл {ПЕРЕСЧЕТ А: если ГЦ] - 0 то АЦ]: = 0 иначе если Л/1 =*= О \/ЦЦ9 j] φ 0 то Л[/]: = 0 иначе А [/]: = 1; ДОБАВЛЕНИЕ K'L: если Л/] ¥= 0 & Д1*, /1 - 0 то Л/]: = 1}} § 4.6. Раскраска вершин графа прим РАСКРАСКА /(4) Z, 47, <?/. Прежде всего нам нужно определить общую организацию алгоритма раскраски с учетом выбранных представлений для объектов и различных эвристик, предлагаемых в § 3.4 Если исходный граф полный, то тогда с ним ничего не происходит, а результатом является тривиальная раскраска, при которой каждая вершина графа получает свою краску. Тогда алгоритм раскраски структурируется на задание начальной тривиальной раскраски и цикл редукции графа (склеивания вершин на расстоянии 2), который повторяется, пока граф не будет редуцирован к полному (не повторяется ни разу, если исходный граф оказался полным). При редукции происходит коррекция раскраски Q, состоящая в замене всех вхождений краски / на краску 1(1 < J), где /и/— краски склеиваемых вершин. При редуцировании исходного графа номера вершин и их краски совпадают. Это удобно, и мы позаботимся о том, чтобы это свойство сохранялось для любого промежуточного редуцируемого графа. В то же время для организации алгоритма важног чтобы вершины графа были бы занумерованы подряд. Эта означает, что при склеивании вершин I и J (I <C J) все вер,- шины, начиная с (/ + 1)-й, получают на единицу меньший номер. Такая же коррекция должна делаться и в текущем состоянии раскраски Q исходного графа. Теперь надо сообразить, как должно выглядеть условие редукции графа. По правилам алгола это должно быть логическое выражение (истинное, если граф неполный, и ложное в цротивном случае). Так как проверку такого условия невозможно записать в виде выражения, содержащего только исходные операции алгола, мы организуем логическую процедуру-функцию ГРАФ НЕПОЛНЫЙ (п), где тг-число вершин в графе, и работающую с графом U как с глобальным объектом, а заодно и вырабатывающую (если граф U не полный) номера I is. J склеиваемых вершин. Такая организация алгоритма тем более удобна, что процесс редукции и перекраски отделяется от способа определения пары склеиваемых вершин. Итак
§ 4.6. РАСКРАСКА ВЕРШИН ГРАФА 165 (75) РАСКРАСКА: {лог проц ГРАФ НЕПОЛНЫЙ (п); знач п; цел п; ТЕЛО ГРАФ НЕПОЛНЫЙ /83/; цел /, /; НАЧАЛЬНАЯ РАСКРАСКА; ЦИКЛ РЕДУКЦИИ /77/} (76) НАЧАЛЬНАЯ РАСКРАСКА /Z, QI: {цел г; для i: = 1 шаг 1 до Ζ цикл Qli]: = i} (77) ЦИКЛ РЕДУКЦИИ /(75) I, U, <?, 7, //: {цел i; и = 0; для U ■= i + 1 пока 7ТЛФ НЕПОЛНЫЙ (I — ί + 1) цикл Р£- ДУ7ПЩЯ} прим РЕДУКЦИЯ /Z, £/, (), 7, «7, г/ заключается в склеивании 7-й и «7-й вершин графа, перенумерации вершин графа, начиная с (/ + 1)-й, и в соответствующей коррекции раскраски Q. Заметим, что перед г-й редукцией граф имеет I — ί + 1 вершин. Итак (78) РЕДУКЦИЯ: {СКЛЕИВАНИЕ; КОРРЕКЦИЯ /82/} прим СКЛЕИВАНИЕ II, U, 7, /, И состоит в прибавлении «7-й строки к 7-й строке (с симметричным преобразованием 7-го столбца). После этого происходит фактическая редукция графа, состоящая в переносе «периферийной» части матрицы смежности так, как это по#а«ано на рис. 4.4. Итак ,'W* 1-й столищ j<J j>J t ' j -v k>J . Ы *>у Рис. 4.4. Редукция матрицы смежности графа. (79) СКЛЕИВАНИЕ: {СЛОЖЕНИЕ; ПЕРЕНОС /81/} прим СЛОЖЕНИЕ /Z, U, 7, /, il. Складывая J-й столбец с 7-м, мы будем, учитывая симметричность матрицы, направлять одновременно результат и в 7-ю строку. Вспомним, что матрица смежности неориентированного графа имеет на диагонали нули (граф без петель). Так как мы складываем столбцы несмежных вершин, после сложения на диагонали останутся нули. Итак ι к J-я строка А
166 ГЛ. 4. РЕАЛИЗАЦИЯ (80) СЛОЖЕНИЕ: {цел к; для к: = 1 шаг 1 до Ζ — i + 1 цикл U[k, I]: = ί/[/, Λ]: = U[k, I] + U[k, J]} прим ПЕРЕНОС /Ζ, U, I, J, il будет состоять в цикле переноса всех столбцов матрицы, начиная с (/ + 1)-го. Правила алгола позволят нам не выделять отдельно случай, когда J > Ζ—г, так как в этом случае цикл не выполнится ни разу. Те компоненты столбцов, которые находятся над /-й строкой, переносятся на одну позицию влево и одновременно заносятся в симметричную позицию матрицы. Компоненты столбцов, находящиеся под J-ш строкой, переносятся на одну позицию влево и одну позицию вверх. Итак (81) ПЕРЕНОС: {цел /; для /: = J + 1 шаг 1 до l—i -+■ 1 цикл {цел к; для к: = 1 шаг 1 до Z—i + 1 цикл если к < / то U[k, /—1]: = U[j—1, к]: = U[k, j] иначе если к > / то Ulk-l, /-1]:= С/№,/]}} прим КОРРЕКЦИЯ /(78) Z, (), /, // напоминает слияние текущих компонент связности в (42—45). Так как по условию / < J> то все компоненты вектора Q, равные /, должны быть заменены на /. Кроме этого все компоненты, большие /, должны быть уменьшены на единицу в связи с перенумерацией части вершин редуцируемого графа. Итак (82) КОРРЕКЦИЯ: {цел i; для i: = 1 шаг 1 до Ζ цикл если Q[i] = J то Q[i]: = I иначе если Q[i]> J то Q[i]: = <?U1-1} прим ТЕЛО ГРАФ НЕПОЛНЫЙ /(75) U, /, /, п/. В качестве эвристики для поиска кандидатов на соцветность (§ 3.4) мы выберем более трудоемкую, но и самую эффективную процедуру нахождения пары вершин / и / (/< /), находящихся на расстоянии 2 и имеющих наибольшее количество разделяющих вершин. Организация алгоритма прямолинейна. Мы заведем величину d с начальным отрицательным значением, где будем поддерживать максимальное из найденного числа разделяющих вершин. Затем переберем все вершины графа, проверяя, не является ли она звездой. Если она такой не является, начинаем выбирать из не смежных с ней вершин, имеющих больший номер,* вершины, находящиеся на расстоянии 2. Если текущее число разделяющих вершин окажется больше d, оно вытесняет предыдущее, а номера вершин запоминаются в / и /. Если после просмотра всех вершин d окажется отрицательным, то это означает полноту графа. Описанное правило рассчитано на связный граф, когда неполнота автоматически обеспечивает существование пары вершин на расстоянии 2 друг от друга. Описанный алгоритм обязательно выдаст требуемую пару вершин, если только она
§ 4.6. РАСКРАСКА ВЕРШИН ГРАФА 167 есть, безотносительно к тому, связен или не связен граф. Однако если граф представляет собой собрание изолированных полных подграфов, то тогда может не произойти никакого разумного присваивания значений величинам / и /. Для этого частного случая нам надо ввести некоторое дополнительное правило склеивания какой-нибудь вершины / одного подграфа с какой-нибудь вершиной / другого подграфа. Автор предлагает читателю в качестве упражнения установить, что, как бы ни происходило начальное сцепление двух полных подграфов, описанный выше алгоритм склеивания будет давать всегда минимальную раскраску: подграф меньшего порядка, однажды зацепившись за подграф большего порядка, будет «вклеиваться» в последний до тех пор, пока больший подграф не поглотит меньший, не увеличившись при этом в разхмерах. В нашем случае мы поступим следующим образом: как только очередная вершина найдет себе несмежную, она подсчитает число разделяющих вершин по некоторому общему правилу, дающему нуль, если вершины не на расстоянии 2. Если d все еще отрицательное, ее значение будет заменено на нуль, а / и / будут загружены номерами этих несмежных ве^щин. Любая «полноценная» пара вершин с ненулевым числом разделяющих вытеснит эту пару, если же этого не произойдет, то мы получим сцепку двух полных подграфов. Итак (83) ТЕЛО ГРАФ НЕПОЛНЫЙ: {{цел d, i; d: = — 1; для i: = 1 шаг 1 до η цикл ПЕРЕБОР ВЕРШИН}; РЕЗУЛЬТАТ /87/} (84) ПЕРЕБОР ВЕРШИН JU, /, /, п, dy И: {цел ;; для /: = i + 1 • шаг 1 до η цикл если U[iy /] = 0 то ОБРАБОТКА НЕСМЕЖНОЙ} прим ОБРАБОТКА НЕСМЕЖНОЙ /U, I, /, п, d, U /Λ Представление графа матрицей смежности в данном случае оказывается для нас очень удобным: число вершин, разделяющих i-ю и ]-ю, равно просто скалярному произведению ι-й и /-й строк матрицы U. Если вершины находятся друг от друга дальше, чем на расстоянии 2, произведение будет равно нулю. Итак (85) ОБРАБОТКА НЕСМЕЖНОЙ: {{цел s; s: = 0; {цел к; для к: = 1 шаг 1 до η цикл s: = s + U[i, к] χ U[j, к]}}; ОТБОР МАКСИМУМА} (86) ОТБОР МАКСИМУМА //, /, d, ι, h si: если s > d то {d: = s; {I: = *;/: = /} (87) РЕЗУЛЬТАТ /(83) dl: ГРАФ НЕПОЛНЫЙ: = d> 0 Этот 87-й шаг завершает программирование задачи экономии памяти в операторной схеме.
ГЛАВА 5 ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ § 5.1. Связь с теорией и практикой О прикладном исследовании. Еще Сократ заметил, что истинным свидетельством глубины знания является понимание его пределов. Вот и сейчас, завершив программирование поставленной задачи, мы вернемся к ее общему анализу с позиций накопленного знания. Автор назвал эту книгу «Введение в теоретическое программирование». В то же время в предисловии им было сказано, что задача экономии памяти будет рассматриваться как пример прикладного исследования. Давайте же попробуем разобраться, что в проведенном исследовании теоретического и что — прикладного. Ко- нечпо, в такой буквальной постановке вопрос звучит несколько наивно. Изучение связи и различия между теоретическим и прикладным исследованием является одной из наиболее глубоких методологических проблем современной науки вообще, а не только математики. Мало того, один и тот же компонент исследования в зависимости от рассматриваемого контекста будет, с одной стороны, казаться созданным по ходу дела как подспорье для достижения конкретной цели, а с другой,— может получить «постоянную прописку» в теоретическом фундаменте целого раздела науки. Например, информационный граф (§ 2.3) оказался для нас хотя и полезным в нужный момент, но вспомогательным, проходным построением, которому не досталось место в результирующей программе. В то же время в теоретическом программировании — это одно из основных понятий, являющееся инвариантом многих полезных манипуляций с программами, а также самостоятельной, явной конструкцией, используемой в важном классе схем программ. Подчеркивая неправильность «абсолютного» противопоставления теоретических и прикладных аспектов, академик С. Л. Соболев неоднократно говорил, что «Нет чистой математики и прикладной математики, а есть математика и ее приложения». Мы, однако, сейчас не будем сильно вдаваться в диалектику единства противоположностей и выжимать из нашего исследования случайные наблюдения, не сравнимые по своей значимости с серьезными работами по методологии и истории математики. В то же время, учитывая вводный характер книги в целом, мы не
§ 5.1. СВЯЗЬ С ТЕОРИЕЙ И ПРАКТИКОЙ 169 будем бояться наивных выражений и придадим некоторую определенность нашей трактовке теоретического и прикладного аспектов задачи экономии памяти. Прикладное исследование характерно прежде всего своей целеустремленностью, направленностью на получение заранее заданного результата. Истоки задачи обычно носят внематематиче- ский характер или, более точно, внешний по отношению к применяемому методу решения. Процесс решения конкретной задачи протекает обычно в некоторой реальной обстановке, характеризующей возможности и ограничения в способах решения, которые также приходится рассматривать как заданные. Говоря о различии между теоретическим и прикладным исследованием, не следует также забывать, что последнее оказывается, как правило, более универсальным по своей природе. Связи прикладного исследования с «внешним миром» более богаты и много· факторны по сравнению с четко выделенными и, по возможности минимальными предпосылками теоретической работы. Теория, несмотря на исчерпывающую полноту своего логического анализа, как ни парадоксально это звучит, всегда в чем-то специализирована, а стало быть, ограничена. Она подчеркнуто отмежевывается от любого утверждения или условия, не включенного в систему исходных определений или посылок. Кстати говоря, забывание этого факта — одна и& распространенных методологических ошибок в исследованиях, лежащих на стыке между теорией и практикой. После этих общих слов вернемся к нашей задаче. Прежде всего мы подчеркнем, что то, с чем читатель познакомился,— это еще только исследование, а не решение прикладной задачи. Как пример полного решения, наше изложение не имеет ни начала, ни конца, хотя те эта"пы, через которые мы прошли в первых четырех главах, являются неотъемлемой и главной частью работы. Говоря об экономии памяти как о прикладной задаче, мы прежде всего должны были бы представить тот реальный процесс, человеческую или иную деятельность, в которой возникает рассматриваемая задача. В нашем случае это могло бы быть конструирование транслятора с некоторого алгоритмического языка, в котором мы хотели бы организовать автоматическую экономию памяти в транслируемых программах. Другим примером могла бы быть разработка конкретной библиотеки программ для бортового вычислителя саг молета, где малый объем оперативной памяти требовал бы ее максимальной экономии. Связь с реальными программами. Анализируя упомянутый процесс, в котором требуется решение задачи об экономии памяти, мы, во-первых, должны были бы научиться строить операторные схемы, отправляясь от того вида программ, в котором они требуют экономного распределения памяти для своих величин. В случав транслятора это мог бы быть либо начальный вид программы, вы
170 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ раженной на входном алгоритмическом языке, либо некоторая промежуточная форма внутреннего представления программы во время трансляции, либо, наконец, упомянутая в § 1.1 символическая форма машинной программы. Для каждой из таких форм нам надо было бы найти правила выделения операторов, их аргументов и результатов вместе с сопоставленными им величинами, а также указания всех возможных передач управления от одного оператора к другому. Очень поверхностно мы затрагивали эти проблемы, рассматривая примеры в первой главе. На деле соответствующие правила должны быть точно определены и запрограммированы аналогично самим алгоритмам непосредственной экономии памяти. Изучение этой проблемы сразу же показало бы нам ограниченность нашей теории. Главных пробелов у нас два. Первый — это наличие в реальных программах величин с индексами, обозначающими компоненты векторов, матриц и вообще многомерных массивов. Спрашивается, что считать аргументами и результатами оператора cli, /]: = c[i, /] + a[i, к] χ b[k, /]? (А) Один из ответов на этот вопрос, например, таков, что если мы все равно не можем проследить, каковы значения индексов, мы будем считать, что аргументами и результатами оператора такого рода являются все массивы целиком, т. е. как будто оператор имеет вид с: = F(C, a, b). (В) Не углубляясь в проблему по существу, отметим только, что задача экономии памяти при наличии массивов заметно усложняется. Вот два каверзных вопроса: (1) Есть массив Μ из 30 ячеек памяти и два массива К и L по 10 ячеек каждый. Массивы К и L не совместимы друг с другом, но совместимы каждый с Μ. Если экономия памяти будет делаться путем склеивания вершин графа несовместимости, то после вклеивания, скажем, К в Μ массив L станет несовместимым с массивом М. В то же время очевидна такая экономия, когда массивы К и L налагаются оба на разные участки массива Μ размерами по 10 ячеек каждый. Как учитывать такие специфические совмещения массивов разной длины, которыми, естественно, не хотелось бы пренебрегать? (2) Присваивание величине х, т. е. обнаружение ее в качестве результата оператора, имеет в схеме программы двойное назначение: оно обязательно прерывает некоторый маршрут, так как χ в результате присваивания, как говорят в американских статьях, «получает новую жизнь» и, возможно, начинает новый маршрут этой величины. Это свойство присваивания играет фундаментальную роль для всей теории. Если мы буквально применим это толкование присваивания к оператору (В), который в схеме был бы
§ 5.1. СВЯЗЬ С ТЕОРИЕЙ И ПРАКТИКОЙ 171 образом оператора (А), взятого, скажем, из программы перемножения матриц, то мы совершим грубую ошибку. Действительно, присваивание некоторой компоненте c[i, /] массива с хотя и означает, что массив с стал «другим», однако он все же стал не настолько другим, чтобы прервать информационные связи от других выработанных ранее компонент этого же массива к их более поздним исследованиям. Второй пробел — это учет существования подпрограмм, работающих при разных вызовах с разными величинами. В примере 11 § 1.4 мы вывернулись, используя в обращениях к процедуре вещ проц F(r) два вызова с одним и тем же фактическим параметром F(x). Попробовав начать сразу с общего случая, мы столкнулись бы с немалыми трудностями. Укрупнение операторов. Другой источник альтернатив в правилах выделения операторов, аргументов и результатов возникает при рассмотрении нашего исследования с другого конца — фактической реализации найденных алгоритмов экономии. Элементарный анализ составленной программы показывает, что экономия памяти характеризуется большим объемом вычислений. Вычисление матрицы смежности U[i: /, 1: I] графа несовместимости по заданным матрица^начальных R[i: I, 1: η] и транзитных ТЦ: Ζ, 1: п] операторов (§ 4.5) требует 12χ η действий, где I — число областей действия, а п — число операторов. Нахождение канонического распределения памяти и транзитных операторов требует вычисления q + 21 транзитивных замыканий. В то же время, если считать в машинных командах, число элементарных операторов в символических,программах исчисляется многими сотнями, а стало быть, общий объем вычислений будет выражаться десятками и оотнями миллионов машинных операций. Поэтому желательно переход от команд программы к операторам схемы сделать не таким буквальным: по возможности укрупнить операторы и сократить число величин, подлежащих экономии по общему алгоритму. Опять-таки, не входя в детали, рассмотрим возможные пути укрупнения операторов. Если рассматривать хорошо организованные и, так сказать, реальные программы, то в них всегда можно заметить такие участки, где вычисления идут «подряд», не прерываясь передачами управления. Эти участки так и называют линейными участками программы. При абстрактном рассмотрении программ в/виде графа переходов соответствующие цепочки вершин называются линейными компонентами графа. Более точно, линейной компонентой называется такая цепочка вершин графа, которая не содержится целиком ни в какой другой цепочке. Возьмем любую такую компоненту и разделим все относящиеся к ней полюсы на три категории. Мы назовем аргументами линейной компоненты I такие аргументы а, для которых существуют маршруты информационных пар вида (гг, а), содержащие хотя бы один оператор, не-
172 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ [а I S л ш Л - - \: тр [Л ГЛ / 4:U-I Ш ч··. И i^Vf мл ГЛ ^w^v ГЛ (Л ^\q^j \л \ б) а) Рис. 5.1. Редукция линейных компонент графа переходов. а) До редукции: 35 операторов, 26 областей действия, б) После редч 14 операторов, .10 областей действия·
§ 5.1. СВЯЗЬ С ТЕОРИЕЙ И ПРАКТИКОЙ 173 принадлежащий Z. Аналогично, результатами компоненты I называются такие результаты г, для которых существуют маршруты информационных пар вида (г, ау), содержащие хотя бы один оператор, не принадлежащий Z. Все остальные полюсы характерны тем, что маршруты их информационных пар целиком содержатся внутри I. Такие информационные пары естественно назвать внутренними, а сопоставленные им величины тоже внутренними, или локальными. Совершенно очевидно, что заняться совмещением локальных величин друг с другом в пределах линейной компоненты можно с помощью гораздо более простых правил, рассмотренных в § 1.2. Осуществив такую внутреннюю экономию локальных величин каждой компоненты, мы можем потом для всех этих величин отвеЬти один участок памяти, по длине равный максимальной ширине информационных связей внутренних величин, найденной среди компонент. После этого операторная схема подвергается редукции, состоящей в замене каждой линейной компоненты I одним оператором, аргументами и результатами которого являются только что определенные нами аргументы и результаты компоненты Z. Естественно, что при таком подходе существенно сокращается число как операторов, так и полюсов, формирующих операторную схему. На рис. 5.1 показан пример редукции линейных компонент исходной операторной схемы в укрупненные операторы. Факторизация. Непосредственным обобщением этого подхода является факторизация операторной схемы на так называемые гамаки. Гамаком называется такой подграф g графа G (в данном -случае графа переходов), для которого существуют две принадлежащие ему вершины, а (вход) и ζ (выход), обладающие следующими свойствами: — все дуги из а ведут в гамак; — любой путь, ведущий в гамак извне, проходит через а; — все дуги в ζ идут из гамака; — любой путь, идущий из гамака вовне, проходит через ζ. Гамак интересен тем, что его можно «стянуть» в одну вершину, не нарушая отношений смежности между остальными вершинами графа. Можно, далее, определить минимальный гамак, как гамак, не содержащий в себе никакого другого гамака. Для гамаков, так же как для линейных компонент, можно определить их аргументы, результаты и внутренние величины. Выделение гамаков и линейных компонент позволяет разложить (факторизовать) глобальную экономию памяти в пределах всей операторной схемы на следующие этапы. Сначала в схеме выделяются линейные компоненты, в пределах которых производится экономия локальных величин по упрощенным правилам. После этого в схеме выделяются минимальные гамаки (по отношению к которым только что обработанные линейные компоненты уже
174 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ редуцированы в элементарные по отношению к гамакам вершины)- Для каждого гамака задача экономии памяти решается отдельно- в отношении его локальных величин, после чего эти гамаки 1-го· ранга редуцируются в вершины — элементарные операторы ш> отношению к остальной схеме. В полученной схеме снова выделяются линейные компоненты и, стало быть, только что описанный двухчастный этап повторяется снова. Этот процесс повторяется до тех пор, пока после очередной редукции схема не превратится в одну или несколько изолированных вершин. Таким образом, решение задачи экономии памяти большого объема свелось к последовательности задач, каждая из- которых может иметь существенно меньший объем вычислений. Поскольку сложность алгоритмов экономии памяти пропорциональна по крайней мере квадрату числа вершин в графе переходов,, такая факторизация, хотя и приводя к решению нескольких задач вместо одной, может давать большой выигрыш во времени, хотя и за счет, быть может, несколько худшего распределения памяти. Рис. 5.2 содержит пример факторизации операторной схемы. Рис. 5.2. Факторизация графа переходов. Магазинное распределение памяти. Оба способа уменьшения объема задачи экономии памяти основаны на том, что мы умеем выделять такие части программы, в которых гарантированно содержатся маршруты интересующих нас информационных связей. Не без умысла мы назвали величины, реализующие такие внутренние информационные связи, локальными. Вспомним теперь, что такой точно термин имеется и в алголе. Локальными в блоке являются те величины, описания которых помещены в начале данного блока. Отвлекаясь ради простоты изложения идеи от наличия процедур в алголе, мы можем по некоторому размышлению заметить, что из помещения описания величины в некоторый блок автоматически следует, что все маршруты информационных пар, ре·
§ 5.1. СВЯЗЬ С ТЕОРИЕЙ И ПРАКТИКОЙ 175 ялизуемых через эту величину, будут проходить только через операторы, образующие данный блок. Два блока алгольной программы называются параллельными, если в тексте программы ни один из них не вложен в другой. В свете сказанного очевидно, что локальные величины параллельных блоков никогда не конкурируют друг с другом и поэтому могут размещаться на одном и том же участке памяти. Отсюда вытекает очень простой способ экрномного распределения памяти для алгольных программ, имеющих блочную структуру. Будем считать, что ячейки памяти, отводимые для хранения величин, располагаются сверху вниз, при этом занятый участок памяти находится наверху, а свободный — внизу. Их разделяет рабочая точка. Сначала рабочая точка находится наверху — вся память свободна. Память распределяется при однократном движении слева направо вдоль текста программы. Тогда правило распределения таково: пусть мы при движении по программе проходим открывающую скобку блока В и пусть для размещения величин, локальных в этом блоке, требуется I ячеек. Тогда в момент лрохождения открывающей скобки мы,сдвигаем рабочую точку на I ячеек вниз и на только что занятом участке размещаем локальные величины блока В. При прохождении закрывающей скобки блока В мы подымаем рабочую точку вверх на те же I яче- «ек. При таком подходе участок памяти, занятый последним, освобождается первым. Потому-то этот способ распределения памяти называется магазинным — от слова «магазин» в огнестрельном оружии: там точно так же патрон, снаряженный в магазин последним, выстреливается первым. На рис. 5.3 показан пример магазин- лого распределения памяти в нашей программе ЭПОС, имеющей развитую блочную структуру. Участки памяти в магазине помечены номерами блоков, к которым они относятся. Тела процедур размножены и подставлены в места их вызова. Схемы и программы. При применении разработанных нами алгоритмов экономии памяти к реальным программам возникает «еще одна проблема, которая, хотя и затрагивалась содержательным анализом, осталась тем не менее за рамками теории. Наша теория гарантирует при перераспределении памяти сохранение множества маршрутов информационных пар, но ничего не говорит о том, что программа (не схема, а программа!), полученная из исходной таким преобразованием, будет работать так же успешно, как и исходная. Честно говоря, у нас с вами, читатель, нет сомнений в этом, но это всего лишь уверенность в правильной постановке задачи и в корректности основополагающего определения вычисляемости одной схемы другой (§ 2.2). Тем не менее, строгого доказательства корректности распределения памяти в применении к программам мы не имеем и "в рамках нашего рассмотрения не можем иметь и в принципе.
176 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ 1 i> 1 1 ^ 3 5*. , а ι l3 |^ ·^ !: ^ ^ ^ -I ^ ^| °о *»·» 1 l·^^ ι041 "^ 1^. '^ ρ·- !5 * |S8·- ρ '" k* «5: ·*: £ «. Jc- §* t§ - ten рЧ hH N^i W-> p·-. *Vj к*1-. U~^" It™ fe:.~_ * Ί & 1 csj 1 b^ !*§·-. i§·^ fe^j Ν ^ te-ч к- ■**'l a·* *J- ч 5^ 1 Iй Ч г^Ч ks-^l кч fe^l |ϊ5 ξ| N4 k-l s;^| f?4 p?*-i !§-ν| V- s^— 1 Si кг s «§ со ^§g з»· о о я σί О Ε a ctf Si и s Ρ* и о о о « СО 1.0
§ 5.1. СВЯЗЬ С ТЕОРИЕЙ И ПРАКТИКОЙ 177 Проанализируем кратко, чего же нам не хватает. Прежде всего у нас нет определения, что такое программа, что такое ее работа и что значит сохранение работы при преобразовании программ. Нахождение таких определений — это, по существу, расширение нашей теории и включение указанных понятий в круг математического рассмотрения. Очевидно, что это расширение теории должно быть тесно связано с уже введенными строгими определениями с тем, чтобы без труда усматривать в формальной программе ее схему и, наоборот, имея факт, установленный для схемы, хорошо представлять, для каких программ этот факт полезен. Только что сказанная фраза уже дает понять, как связаны понятия программы и её схемы. Человек сочиняет программу, машина ее исполняет. Человек не может передать программу машине, не написав ее сначала, т. е. не придав ей некоторую внешнюю текстовую форму. Текст программы сам по себе еще недостаточент чтобы решить задачу, вызвавшую появление этой программы. Только в машине есть устройство, которое придает смысл, или как говорят, интерпретирует, например, символ операции + в программе или связывает с символом величины χ определенное содержимое. Таким образом, мы вдыхаем жизнь в программный текст, лишь дав ему некоторую интерпретацию, существующую по отношению к составным элементам программы сама по себе, отдельно, в виде исполнительных устройств машины или по крайней мере в виде другой «сверхпрограммы» — точного описания правил работы этих устройств. Это разделение нашего- знания о программах — на текст и на его смысл — находит свое отражение в разделении описания алгоритмических языков на синтаксис (учение о тексте) и семантику (учение о смысле). Возвращаясь снова к операторным схемам и программам, мы приходим к бесспорному наблюдению, что схема — это есть некоторая абстракция текста программы. В ней содержится кое-что из того, что можно увидеть, прочитать в тексте программы, не выполняя его. Наши операторные схемы содержат имена операторов и величин, а также перечень возможных передач управления от одного оператора к другому. Для того чтобы превратить схему в программу, нам нужно дать интерпретацию формальным символам схемы. В нашем случае дать интерпретацию величинам — это значит описать множества их значений (задать предметную область), дать интерпретацию оператору — значит задать значения его результатов и способ выбора преемника (оператора, выполняемого вслед за данным) как некоторую конкретную функцию значений его аргументов. Эта интерпретация позволит описать точно процесс выполнения программы. Далее, для программы можно определить ее аргументы и результаты. Тогда естественным определением работы программы будет вычисление своих результатов как некоторой результирующей функции своих аргументов.
178 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ Если две программы работают одинаково — это значит, что они вычисляют одну и ту же функцию. И вот теперь узловой момент о связи теории схем программ с самыми программами. Пусть мы располагаем некоторым фактом F о схеме G. Первое, что мы должны уметь, это, задав некоторую интерпретацию /, превращающую схему G в программу P=(I, G), истолковать факт F как некоторый факт (/, F) о программе Р. Так вот, наш факт о схеме G интересен и всеобщ, если из справедливости F вытекает справедливость всех (/, F), какова бы ни была интерпретация /. В нашем случае, имея в качестве «схемного.» факта утверждение о вычисляемости одной схемы другой (С У~ G), мы хотели бы иметь как следствие из него, что программы (/, С) и (/, G) будут вычислять всегда одну и ту же функцию, какова бы ни была интерпретация /. Мы не будем развивать дальше наших рассуждений, потому что сделаем это аккуратно для другого класса схем во второй части книги. Заметим только для успокоения, что такого рода обоснование нашей теории экономии памяти на самом деле имеет место. Нам осталось сделать некоторый чисто программистский комментарий к реализационной части нашего исследования. Составленная нами программа носит вполне реальный характер, хотя, ради демонстрации метода структурированного программирования и из-за некоторой бедности алгола 60, мы на первый план поставили естественность, или, более точно, прямолинейность реализации. Каковы другие, не рассмотренные нами факторы, которые надо было бы учесть при аккуратном программировании? Во-первых, структурированное программирование, по крайней мере в выбранном нами формализме, создает слишком много блоков. В некоторых трансляторах с алгола вход в блок программируется с большими накладными расходами, неоправданными ради описания, например, одного параметра цикла или другой мимолетной величины. Возможно, что процесс структурированного программирования должен после завершения непосредственного построения программы и ее проверки сопровождаться систематическим ее преобразованием, например, сокращающим количество блоков. Во-вторых, нам надо было бы более детально проанализировать баланс между расходом памяти и расходом времени при экономии памяти. Для каждой задачи есть свои нижние оценки временной или емкостной сложности, неуменьшаемое время работы, несокращаемые объемы памяти. Однако за пределами этих абсолютных оценок можно экономить на одном за счет другого. Например, мы могли бы вовсе не формировать матрицу R (§4.5), извлекая нужное множество начальных операторов из распределения полюсов всякий раз, когда в нем возникает потребность. При построении ка-
§ 5.2. ИСТОРИЧЕСКИЙ ОБЗОР 179 нонического распределения памяти (§ 4.4) мы, наоборот, могли бы для каждой исходной величины из числа xv . . ., хт построить заранее множество воспринимающих ее операторов, образовав из соответствующих шкал матрицу порядка т χ η, сократив время, затраченное на построение аргументных множеств, в q/m раз (по одному разу на каждую величину вместо по одному разу на каждый результат). Подобного рода конструкторские вопросы нужно решать с учетом того реального контекста, в котором применяется алгоритм экономии памяти. Наконец, даже находясь в заданных рамках общей организации алгоритма, мы могли бы придумывать разные приемы повышения эффективности нашего алгоритма. От одного ухищрения мы не удержались, когда построили вектор аргументных полюсов а в расчете на наиболее частой случай однократного вхождения величины в оператор в качестве аргумента. Например, мы могли бы сильно сэкономить на времени построения графа несовместимости, задавая в качестве начального значения его компонент не нули, а результат перемножения множеств Rt на Д7·, где Rt — множество начальных операторов г-й величины канонического оператора. Это позволяла бы нам в ряде случаев даже и не начинать проверку непустоты пересечений множеств типа R (} Т. Сам процесс попарного перемножения множеств можно было бы прерывать немедленно по обнаружении ненулевого произведения компонент. Подобного рода усовершенствования многими воспринимаются как наиболее «аппетитная» часть программирования, отражающая его изобретательный и творческий характер. На самом же деле только целесообразность, к тому же правильно понимаемая, может быть судьей во внутренних спорах по поводу оснащения «основного» хода вычислений специальными приемами. В каждом случае желательно иметь оценку улучшения показателей программы при учете различных особых случаев. Истинное чувство меры в соотношении достоверной простоты и менее надежной изощренности приходит только с опытом и зрелостью, как и в каждом виде творческой деятельности. § 5.2. Исторический обзор Рассказывая о задаче экономии памяти, автор подчинил способ изложения дидактическим целям в попытке сочетать полноту рассмотрения с естественностью в развитии темы. И хотя в целом решение задачи является довольно элементарным, оно опирается на ряд нетривиальных идей, до которых оказалось не так просто додуматься. От первой практической постановки задачи до создания полной теории в ее наиболее естественном выражении прошло свыше десяти лет, а процесс ее обобщения на более сложные классы операторных схем продолжается еще и сейчас.
180 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ Мы заключим наше рассмотрение задачи об экономии памяти разбором работ, приведших к ее решению и взятых в их временной последовательности. Этот исторический обзор будет не полон, он ограничен работами, лишь непосредственно повлиявшими на создание теории, либо так же непосредственно использовавшими ее результаты. Алгоритм Штаркмана. Первой работой, рассматривающей экономию памяти как самостоятельный этап в процессе программирования, была статья В. С. Штаркмана «Блок экономии рабочих ячеек в ПП-2», опубликованная в известном 1-м выпуске «Проблем кибернетики» (М., Физматгиз, 1958), утвердившем становление научных основ программирования в СССР. В работе* по существу, полностью решена задача экономии внутренних величин на линейных участках программы. Эта задача рассматривается в контексте работы транслятора (называншегося в то время программирующей программой — ПП), формирующего линейные участки машинной программы для _ трехадресной ЭВМ при трансляции арифметических операторов исходной программы. Идея алгоритма изложена в работе настолько ясно, что мы просто предоставим слово автору. «...Рабочими ячейками в ПП-2 называются ячейки, предназначенные для хранения промежуточных результатов, т. е. таких результатов, которые используются в данном операторе и не используются ни в каком другом операторе. Из самого такого определения, очевидно, следует, что ячейки, являющиеся рабочими для одного оператора, могут с успехол! использоваться как рабочие и в другом операторе. Совершенно очевидно, что общее число нужных в программе рабочих ячеек равно максимальному числу рабочих ячеек по всем операторам программы. Отсюда следует, что для экономии рабочих ячеек в программе нужно экономить их для каждого оператора в отдельности. ...Назовем областью существования промежуточного результата совокупность' приказов, при выполнении которых мы не можем использовать ячейку, хранящую данный промежуточный результат, для хранения другого результата. Такая совокупность, очевидно, начинается с приказа, породившего результат, и заканчивается приказом, выполняющимся перед последним приказом из числа тех, которые данным результатом пользуются. Очевидно, что промежуточные результаты с непересекающимися областями существования безболезненно могут помещаться в одну и ту же ячейку памяти. ...Экономия рабочих ячеек... осуществляется за один «просмотр» оператора следующим образом. Все приказы оператора последовательно перебираются снизу вверх, начиная с последнего и кончая первым. В процессе перебора ведется таблица (Г), где
§ 5.2. ИСТОРИЧЕСКИЙ ОБЗОР 181 на каждом этапе перечислены, условные числа (символические обозначения.— А. Е.) тех промежуточных результатов, для которых очередной «просматриваемый» приказ принадлежит их области существования. Делается это так: если в III (результатном — А. Е.) адресе приказа нам попадается условное число промежуточного результата, то в Г отыскивается строка, содержащая его, и очищается, если же условное число попалось в I и И адресах и «просмотр» Τ показал, что его там нет, что отыскивается самая верхняя свободная строка Г и в нее записывается выбранное условное число. И только в том случае, когда свободных строк внутри Τ не оказывается, к ней присоединяется еще одна строка с выбранным условным числом. При такой системе, во-первых, в каждую строку Τ попадают условные числа промежуточных результатов с непересекающимися областями существования, во-вторых, условные числа результатов с пересекающимися областями попадают обязательно в разные строки и, в-третьих, количество строк в Τ в процессе просмотра, увеличиваясь с нуля, в конце достигает числа нужных нам рабочих ячеек.» Главной догадкой Штаркмана является организация экономии рабочих ячеек путем обратного просмотра команд оператора. Тем самым маршрут каждой величины обозревается, начиная с последнего использования. Это в точности соответствует требованию общей теории: находясь в пределах маршрута, данная величина конкурирует с результатами всех внутренних операторов. В общем случае множество внутренних операторов Τ = Ε Π L, где Ε — это прямое, a L — обратное транзитивные замыкания. Очевидно, что для линейнои^прьграммы Τ = L, что и использовал Штаркман. Алгоритм Штаркмана был усовершенствован при разработке еще одного раннего транслятора, описанного в книге А. П. Ершова «Программирующая программа для быстродействующей электронной счетной машины» (Мм Изд-во АН СССР, 1958). В этом трансляторе, хотя и не вполне осознанно, была реализована идея явного указания информационных связей в пределах линейного участка программы. В терминах трехадресных команд это выглядело следующим образом: если при построении команд линейного участка в к-ю по порядку ячейку направлялась очередная команда, то третий адрес у нее оставался незаполненным. В тех же {первом или втором) адресах последующих команд, которые должны были бы использовать результат к-й команды, ставился номер к. Это позволяло осуществлять экономное распределение памяти не как переобозначение внутренних величин, а сразу как некоторое назначение рабочих ячеек результатам и аргументам ее команд. При таком задании информационных связей алгоритм Штаркмана выглядел следующим образом. Таблица Τ имеет вид логи-
182 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ ческой шкалы, так что Г U ] соответствует i-й рабочей ячейке. При просмотре очередной команды в Τ помечены единицами занятые в данный момент рабочие ячейки. При обследовании аргументного адреса А очередной команды используется результатный 3-й адрес R команды, номер которой указан в адресе А. Если он пуст, то в шкале Τ ищется первый ненулевой разряд, него номер задает рабочую ячейку, которая ставится в R и в А. Если R не пуст, то это значит, что ему уже назначена указанная там рабочая ячейка, которая также направляется и в Л. При обследовании результатного адреса текущей команды стоящая в нем рабочая ячейка отмечается в шкале Τ как свободная. На рис. 5.4 показана работа / Ζ δ 4 с β 7 δ 8 Χ Χ χ χ χ χ χ χ χ χ χ rZ t1 r4 tz rS U r16 td X X Γδ ti Mf tf rZ7 tf X X r2 tf rU tz r8 t4 Мб t3 rZ tf rS t4 Мб td r32 tz rZ ; t1 I r4 tz rS η Мб td r3Z tz r3 tf ' rff tf rZ7 tf У У \ U \rZ \rZ \rZ \rZ \rZ V2 \rZ \rZ \rZ \/4 \ρδ γώι \rff \sSZ7 \rZ7 •/a r4 /& ρδ2 rdZ rdZ riZ rdZ rdZ rdZ /4б Мб Мб Мб Мб Мб Мб Мб /г8 г8 г8 г8 г8 г8 г8 г8 f Ζ δ 5 б 7 8 9 X Χ Χ χ χ χ χ χ χ χ χ f tf Ζ tz δ U 4 td χ я б tf 7 tf 8 tf X X f tf Ζ tz "5 U 4 td f tf δ tu 4 td 5 tz tf tz U td tz tf tf tf У у I /1 \f \f \f \f f \f f \f f /1 \f Vf \f V и /f f /1 f f f f f f /f f f f f f J f I A f\ f\ f\ f\ f\ / / tf tZ td · П tj tZ tz tif. Ю δ) Рис. 5.4. Пример работы алгоритма Штаркмана. а) Оригинальная форма, б) Модификация в ПП для БЭСМ. алгоритма Штаркмана для линейной программы вычисления у =. хЪ9 (пример 5 из § 1.2) как в оригинальной форме, так и в его модификации (внешние величины χ и у не совмещаются с рабочими ячейками). На каждом этапе просмотра очередная команда и таблица Τ изображаются дважды: команда со старыми и новыми обозначениями, таблица до обследования результатного адреса и после обследования. Экономия памяти в линейных программах получила дальнейшее развитие в работе А. 11. Ершова «О программировании ариф-
§ 5.2. ИСТОРИЧЕСКИЙ ОБЗОР 183 метических операторов», опубликованной в Докладах Академии наук СССР (т. 118, № 3, 1958). В этой работе им было введено рассмотренное нами в главе 1 понятие ширины информационных связей в некотором сечении программы и решена (для частной постановки, обсуждавшейся в § 3.3) задача получения упорядочивания дерева с наименьшей шириной. Замкнутые схемы Лаврова. Принципиальный вклад в решение задачи об экономии памяти внес С. С. Лавров своей работой «Об экономии памяти в замкнутых операторных схемах», опубликованной в 1961 г. в 4-м номере «Журнала вычислительной математики и математической физики». Он ввел понятие операторной схемы, рассмотрел различные варианты распределения памяти как эквивалентные преобразования, состоящие в переобозначении величин, ввел понятие маршрута, канонического распределения памяти и графа несовместимости. В то же время в созданной им теории отсутствовали некоторые компоненты, что, в частности, не позволило ему решить задачу экономии памяти в общем случае. В некотором смысле работу Лаврова можно рассматривать как попытку прямого обобщения алгоритма Штаркмана на максимально возможный общий случай. Вернемся к демонстрации алгоритма, приведенной на рис. 5.4, а). Мы видим, что работа алгоритма состоит из двух частей: заполнение таблицы Τ и выбор новых обозначений величин на основе изучения таблицы. Обе эти части из конструктивных соображений объединены в один просмотр программы, но могут рассматриваться и раздельно. Преобразуем несколько таблицу Τ так, чтобы ее можно было бы рассматривать отдельно от программы. Для этого достаточно номер команды вместо использования его как номера строки получившейся матрицы внести в позиции таблицы. Таким образом таблица становится множеством пар — (команда, величина): При этом различаются состояния таблицы «до выполнения» и «после выполнения» команды. Для такого различения будем рассматривать соответственно пары (я, К) и (К, х), где К — команда, а χ — величина. В результате у нас получается некоторое множество пар (рис. 5.5), которое Лавров называет множеством загрузки М. Смысл отнесения пар к множеству загрузки очевиден: (χ, Κ)ΕζΜ означает, что значение χ должно быть сохранено в момент, предшествующий выполнению К, а (К, х) означает то же для момента после выполнения К. Глядя на множество загрузки уже в нашем случае линейной программы, можно сформулировать ряд его свойств как конструктивной основы распределения памяти: 1. Множество Μ строится движением по программе навстречу передачам управления: пары, содержащие величину х, начинают заноситься в Μ с момента появления χ в качестве аргумента и перестают с момента появления χ в качестве результата.
184 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ 2. Каждая пара в таблице Τ соотносится одной из вновь назначаемых величин; другими словами, новое распределение памяти задается как функция L, определенная на множестве М. 3. Множество загрузки по отношению к разным функциям распределения памяти обладает некоторой постоянной структурой, а именно: в нем можно усмотреть подмножества, на которых любая «конкретная» функция L должна сохранять свое значение. 4. К таким подмножествам относятся прежде^ всего маршрутные цепочки, последовательности пар ; (Кгх) (*, К2) (Я2, х) . . . ...(x,Kn-l) (Кп-19 X) (х,Кп)г таких, что Кг вырабатывает х, К2, . . ., -ffn-i н& вырабатывают я, Кп воспринимает я, а в программе любой Κι оказывается преемником Ki-г (i = =,2, . .., и). 5. Маршрутные цепочки, содержащие одну и ту же величину, объединяются в связки, характеризуемые (в случае линейных программ) общей начальной парой (Кгх). Функция распределения памяти должна сохранять постоянное значение на всех парах относящихся к связке, которую Лавров называет областью действия. 6. Разным обла тям действия можно сопоставить одно и то же значение функции распределения памяти в том и только в том случае, если у них нет ни одной пары одинаковой ориентации с одной и той же командой. Распределение памяти, функция которого принимает разные значения μ& разных областях, называется каноническим. Зафиксировав эти свойства множества загрузки, Лавров ищет класс операторных схем, позволяющий гарантировать корректность распределения памяти по указанным правилам. Оказывается, для этого достаточно постулировать свойство 1, которое для линейных программ выполняется автоматически, а именно, потребовать, чтобы любой оператор, от которого дости- / 1 * 5 δ 7 8 9 X | χ | χ | г2 | X г2 | г2 г4 | *Х \ r4 \ r4 \ r8 \ х | гд \ г8 | Мб | X | Мб | Мб | г32 | Χ \ χ \ г2 \ гд \ X | г δ | г8 г11 Χ \ Μ1 \ Мб | г27 | X | r27 \ r32 \ у \ \1S2 \2,г2 \г,г2 \3,г2 \3,г2 Wr2 Us2 \w \5,r2 \м \W \Zr3 \lrff \8,М/ \8,r27 \9s27 2,г4 3,г4 б,г52 б,г32 %г32 Ы2 %г32 8гЪ2 8гЪ2 S,r32 4/-/δ ζΜδ 5,М6 δ,Μδ δ,Μδ 7,Μδ 7,Μδ 8,Мб зМ 4,г8\ 4,г8\ 5,г8\ б,/>8\ ξτδ\ б,г8\ 7,г8\ Рис. 5.5. Множество загрузки в программе для у = а?59.
§ 5.2. ИСТОРИЧЕСКИЙ ОБЗОР 185 эким оператор, воспринимающий х, был бы достижим от некоторого оператора, вырабатывающего х. Операторные схемы, удовлетворяющие этому свойству, Лавров называет замкнутыми. Маршрутная цепочка с величиной χ есть не что иное, как информация, задающая начальный, транзитные и конечный онера- торы некоторого маршрута, реализующего информационную связь t помощью х. Уточнять, какому результату и какому аргументу сопоставлен х, Лаврову не надо, так как в его определении операторной схемы любая величина в любом операторе в качестве аргумента или результата встречается не более одного раза. Свойство 5) формулируется., естественно, в более общей форме, объявляя связанными маршрутные цепочки т и т\ для которых существует последовательность цепочек т, гпц . . ., mk, m\ такая, что любые две соседние имеют общую либо начальную, либо конечную пары. Сравним свойство 6) с критерием несовместимости областей действия, данным в теореме 4 § 2.3. Пусть в каноническом распределении памяти двум областям действия сопоставлены величины χ и х'. Пусть Щх), А(х) и Т(х) соответственно операторы, вырабатывающие х, воспринимающие χ и транзитные для маршрутов, чьи информационные связи реализуются величиной х. Для замкнутых операторных схем критерием несовместимости по Лаврову является непустота множества (R{x)M T(x) U А(х)) П (НЫ') U T(x') U А(х'))\(Н(х) П А{х') [} иД(*0ГМ(*)). (*) В этих обозначениях критерий несовместимости для общего случая выглядит как непустота множества (Щх) U Цх)) П (Д(«0 U Т(х'))\(Т(х) П Па?)). (**) Очень просто показать, что для замкнутых схем (**) вытекает из (*). Действительно, пусть S — оператор принадлежащий каждому из двух маршрутов Μг(х) и Μ2(у) в качестве транзитного или конечного операторов. Из начал этих маршрутов выберем оператор Н1ч ближайший к S. Пусть он начинает маршрут Мг(х). Оператор S является либо концом К маршрута М2(у), либо его транзитным оператором, т. е. от него достижим конец К этого маршрута. Тогда, очевидно, этот К достижим и от оператора Нх* В силу замкнутости есть маршрут Μ (у), для которого Нг является либо начальным, либо транзитным оператором. Отсюда следует, что величины χ и у. несовместимы. Таким образом мы установили, что определение областей действия по Лаврову в точности соответствует определению компонент связности информационного графа, а его критерий
186 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ несовместимости эквивалентен общему критерию на множестве замкнутых операторных схем. Лавров не вводит инварианта, сохраняющегося при «корректных» перераспределениях памяти, постулируя вместо этого свойства «корректных» функций распределения памяти. У него две схемы оказываются эквивалентными, если существует корректное переобозначение величин, превращающее одну схему в другую. Фактически же для того, чтобы определить корректность, Лаврову неявно нужно потребовать неизмененности множества всех маршрутов исходной схемы. В корректных преобразованиях замкнутых операторных схем множество маршрутов не меняется, а стало быть, все перераспределения памяти оказываются обратимыми. Заметим, что в нашем содержательном анализе задачи в § 1.4 незамкнутая схема появилась только в конце (пример 11). Конструктивным выражением теории экономии памяти у Лаврова явилась описанная на алголе процедура построения множества загрузки операторной схемы с ого разбиением на области действия. Общий случай. Первый вариант теории экономии памяти для общего случая был изложен А. П. Ершовым в Докладах Академии наук СССР (т. 142, № 4, 1962) под названием «Сведение задачи распределения памяти при составлении программ к задаче раскраски вершин графов». Схема у Ершова задавалась такжег как у Лаврова: множества операторов и величин, граф переходов двоичная матрица аргументов ||αί7·|| (αί7· = 1, если i-я величина является аргументом /-го оператора) и аналогично устроенная матрица результатов. В теории еще отсутствовали полюсы, информационные связи и информационный граф. В качестве инварианта допустимых распределений памяти рассматривался носитель — множество всех маршрутов (маршрут так же, как у Лаврова, определялся как маршрут величины, а не информационной связи). Допустимыми распределениями памяти были такие распределения, при которых носитель не сокращался. Области действия определялись как компоненты связности носителя, в котором симметричное отношение связности определялось между маршрутами. Такой подход формально требовал (правда, тривиального) доказательства конечности числа областей действия. В работе был.сформулирован критерий несовместимости областей действия (теорема 4 § 2.3), а процедура нахождения множества транзитных операторов была описана как получение двух транзитивных замыканий (множества Ε и L), для которых были приведены рекуррентные формулы их вычисления. В указанной работе Ершовым был сделан шаг в сторону решения задачи экономии памяти для программ, содержащих массивы. Для этого каждой величине приписывался «вес»— целое число*
§ 5 2. ИСТОРИЧЕСКИЙ ОБЗОР 187 указывающее, сколько рядом расположенных ячеек памяти требуется для хранения величины. На всех этапах теории вплоть до раскраски вес величин никак не учитывался. В то же время, учитывая проблему, затронутую нами в итоговом анализе (вопрос {2) в начале § 5.1), для каждого результата в операторной схеме считалось известным, вырабатывается ли он «в целом» или только частично. Начинать маршрут, величины могли только операторы, вырабатывавшие ее в целом. Операторы, вырабатывавшие величину не в целом, обязаны были быть транзитными операторами маршрутов. В 1968 г., в 4-м номере журнала «Кибернетика» А. П. Ершов опубликовал статью «Об операторных схемах над общей и распределенной памятью». В этой работе он ввел понятие информационного графа, где вершинами являются полюсы (аргументы и результаты) схемы, а дуги означают информационные связи от результата к аргументу. В частности, им было показано, что области действия по Лаврову являются компонентами связности информационного графа. На этом формирование общей теории экономии памяти в операторных схемах, по существу, закончилось. Модернизированное изложение теории, практически совпадающее^ содержанием § 2.3, было дано А. П. Ершовым в статье «Аксиоматика распределения памяти» опубликованной в трудах «симпозиума «Теория языков и методы построения систем программирования» (Киев — Алушта, Редакционно-издательский отдел Института кибернетики АН УССР, 1972). Сведение задачи экономии памяти к раскраске вершин графа обратило взоры программистов в сторону теории графов. Одним из первых результатов такого интереса явилась совместная работа А. П. Ершова и Г. И. Кожухина «Об оценках хроматического числа связных графов» (Доклады Академии наук СССР, т. 142, № 2, 1962). Интересно заметить, что один из ее авторов, Г. И. Ко- жухин, пришел к этой работе, интересуясь теорией раскраЪки самой по себе. Им была доказана теорема о соцветных вершинах {теорема 8, § 3.4) и верхняя оценка хроматического числа как функция числа вершин и ребер графа. Вклад другого автора состоял в нижней оценке и в использовании восходящей к А. А. Зыкову трактовки раскраски как последовательного склеивания вершин. В. В. Марты'нюк в статье «Об экономном распределении памяти», опубликованной в 1962 г. в 3-м номере «Журнала вычислительной математики и математической физики», описал приведенное нами в главе 3 построение операторной схемы по произвольному графу несовместимости, а также предложил некоторую эвристику совмещения разновесных массивов. Л. К. Трохан провела в 1962 г. серию экспериментов по раскраске графов 45-го порядка на ЭВМ с использованием всех трех
188 ГЛ. 5. ЗАКЛЮЧИТЕЛЬНЫЙ АНАЛИЗ обсуждавшихся в § 3.4 эвристик, доказавшую практичность даже простейшей эвристики. Опыт практического применения теории экономии памяти в конструировании транслятора был получен при проектировании так называемого альфа-транслятора, транслирующего на машинный язык программы, выраженные на альфа-языке, некотором расширении алгола. Этот опыт был описан в работе Α. Γ1. Ершова, Л. Л. Змиевской, Р. Д. Мишкович, Л. К. Трохан «Экономия и распределение памяти в «Альфа-трансляторе», опубликованной: в сборнике «Альфа—система автоматизации программирования» (Новосибирск, Сибирское отделение издательства «Наука», 1967). В качестве операторов схемы брались линейные участки машинной программы, а также гамаки простой структуры. Тела процедуры трактовалось так, что его первый оператор считался преемником каждого вызова данной процедуры, а преемниками оператора выхода из процедуры — все операторы, стоящие в программе вслед за вызовами. Если оператор имел в качестве аргумента формальный параметр х, то его аргументами считались все величины, подставляемые в вызовах на место х. Аналогично дело обстояло с результатами. Компоненты связности не строились, но учитывалась несвязность и неконкурентность маршрутов величин, описанных в параллельных блоках. Другими словами, если описания любых величин χ и у попадали в параллельные блоки, то они рассматривались в схеме как разные совместимые величины. В качестве величин рассматривались не только скаляры (занимающие одну ячейку памяти), но и массивы (векторы). Граф несовместимости задавался своей матрицей смежности и раскрашивался по первой эвристике. Массивы одинаковой длины совмещались друг с другом целиком, «один в один». При помещении массива А меньшей длины в более длинный массив В делалась попытка разместить в остатке массива В другие величины, совместимые с Z?, но не совместимые с А. К моменту написания этой книги литература, относящаяся к вопросу экономии памяти, содержит уже несколько десятков названий. Эти работы развивают алгоритмическую технику экономии памяти (построение транзитивных замыканий, эвристика раскраски и совмещения массивов), рассматривают экономию памяти в контексте более широких преобразований программ, распространяют теорию на более содержательные классы операторных схем и программ. Само понятие операторной схемы, различные ее свойства или извлекаемые из нее объекты продолжают изучаться в теоретических работах. О некоторых из них у нас еще будет повод поговорить во второй части книги, а в остальном знакомство с дальнейшим развитием этой темы становится предметом специального изучения, выходящего за рамки наших бесед.
ЧАСТЬ II ПРЕОБРАЗОВАНИЯ СХЕМ ЯНОВА ГЛАВА 6 КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ § 6.1. Логические формулы и булевы функции Предмет логики. Логика, подобно арифметике и геометрии,, является одной из математических дисциплин, с предметом которой человек, даже того не ведая, имеет дело с первых лет своей сознательной жизни. Более правильным было бы, пожалуй, сказать, что законы правильного рассуждения о предметах и явлениях, наряду со свойствами форм предметов и количестведными соотношениями между предметами,являются главным содержанием математики, если говорить о ее вкладе в повседневную человеческую практику. Интересно, однако, отметить, что логика, будучи как организующий элемент человеческого общения много старше математики, стала сама объектом математического изучения совсем недавно: по-настоящему лишь в конце девятнадцатого века. Это тем более парадоксально, что математическая логика в чем-то проще многих других^ разделов математики. Этому парадоксу есть свое объяснение, которое, однако, автор не может изложить здесь с должной глубиной. Мы заметим только, что, с одной стороны, математики в течение долгого времени и при этом в целом успешно полагались на здравый смысл в применении законов логического рассуждения, пока конкретный математический материал (обоснование математического анализа, парадоксы теории множеств, неевклидова геометрия) не подвели их к необходимости заняться логическими основами самой математики. С другой стороны, необходимо было достичь высокого уровня абстрактного мышления и своего рода доверия к символике, чтобы правильно найти исходные абстракции логических рассуждений и быть уверенным в универсальной применимости формально выведенных законов логики, выраженных в символической форме. В этой повторительной главе мы дадим краткий обзор одного из разделов математической логики — алгебры логики и исчисления высказываний, который, по мнению автора, обладает многими замечательными качествами. Объекты этой теории и относящиеся к ней задачи сравнительно просты; в то же время доказываемые в алгебре логики и исчислении высказываний свойства и теоремы глубоки и содержательны, применимы к многим явлениям реаль-
190 ГЛ. С. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ ного мира и многое в нем объясняют. Построение теории, будучи весьма стройным и естественным, одновременно содержит в себе, как в зародыше, общую структуру многих богатых и сложных теорий современной математики. Одна из целей логического рассуждения — это установление истины, т. е. возможности достоверно подтвердить или опровергнуть некоторое высказывание. Уже в одной этой фразе содержатся одновременно некоторое наблюдение и некоторое ограничение. Человек рассуждает, произнося фразы на человеческом, или, как говорят, естественном языке. Ограничение состоит в том, что мы рассматриваем лишь такие фразы естественного языка (высказывания), о которых имеет смысл говорить, что они правильны или неправильны, истинны или ложны. Наблюдение подсказывает нам, что свойства истинностиуйли ложности оказываются взаимно дополняющими; другими словами, естественный язык устроен так, что если мы имеем некоторое ложное высказывание («Москва — столица Франции»), то всегда можно высказать его отрицание, являющееся истиным высказыванием («Неверно, что Москва — столица Франции»), и наоборот. При этом такой переход от утверждения к его отрицанию можно осуществить' простой перестройкой фразы, не вникая в ее смысл (с этой точки зрения переход от ложного высказывания «Москва — столица Франции» к истинному —«Париж — столица Франции» или «Москва — столица СССР»— это не то правило перехода от утверждения к его отрицанию с помощью приставки «неверно, что...», а содержательная подмена одного высказывания другим, выполняемая за рамками формальных законов логики. Анализируя высказывания, образующие цепочку логического рассуждения, мы обнаруживаем в нем то, что обычно называется исходными фактами, т. е. самыми простыми суждениями, истинность или ложность которых установлена заранее, или, более точно, средствами, находящимися за рамками данного логического рассуждения. Правила естественного языка позволяют из исходных фактов составлять более сложные производные высказывания. При этом, как и в случае правила отрицания, мы усматриваем, что существуют такие правила построения сложных высказываний, в которых свойство высказывания быть истинным или ложным зависит только от истинности или ложности составляющих исходных фактов и от того, каким образом они комбинируются в сложное высказывание. В естественном языке эти правила выглядят как сочленение высказываний с помощью следующих выделенных слов: НЕВЕРНО, ЧТО (НЕВЕРНО, ЧТО Москва - столица Франции) — отрицание; И (шел дождь И шли два студента) — конъюнкция; ИЛИ (он пьет ИЛИ он курит) — дизъюнкция;
§ C.i. ЛОГИЧЕСКИЕ ФОРМУЛЫ И БУЛЕВЫ ФУНКЦИИ 191 ВЛЕЧЕТ (преступление ВЛЕЧЕТ наказание, бузина в огороде ВЛЕЧЕТ дядьку в Киеве, свист рака ВЛЕЧЕТ молоко от козла, 2x2 = 4 ВЛЕЧЕТ, что Волга впадает в Каспийское море, но НЕВЕРНО, ЧТО истина ВЛЕЧЕТ ложь) — импликация; ИЛИ . . . ИЛИ (ИЛИ он украл пальто, ИЛИ у него укради пальто) — альтернатива; ТО ЖЕ, ЧТО (х простое число — ТО ЖЕ, ЧТО χ делится только на себя и единицу) — тождество. Мы позволили себе привести в качестве примеров несколько расхожих выражений, чтобы резче подчеркнуть, что можно точно говорить об истинности или ложности сложных высказываний, даже не задумываясь об их содержательном значении, если только правила понимания указанных союзов и оборотов (называемых логическими связками) раз и навсегда оговорены. Эти правила употребления становятся, как обычно, особенно четкими, если их представить в символической форме, в которой исходные факты будут изображаться как независимые логические переменные, принимающие два значения f (ложь) и t (истина), а логические связки — как логические операции с двумя аргументами: х&уу- конъюнкция (другое обозначение: xf\y; x\J у — дизъюнкция; xZD у — импликация (другое обозначение: х-± у; χ называется посылкой, а у — заключением импликации); χ 4- У — альтернатива; χ = у — тождество; и как операция над одним аргументом: ~]х — отрицание (другое обозначение: х). Значениями логических операций являются те же два значения f и t. Таким образом эти операции полностью описываются таблицами своих значений, называемыми таблицами истинности X i t ix t ί χ ϊ £ t t У f t ι f t x&y f f f t xVy I t t t xDy t t f t *+y f i t f х=У t f i i Глядя на эти таблицы истинности и на задающие их логические связки, можно сделать следующее наблюдение: если сложное высказывание осмысленно, то его смысл не противоречит значе-
192 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ нию истинности, полученному по правилам вычисления логических операций. Именно это наблюдение (не теорема!) дает нам основание верить в полезность далее развиваемой теории. Логические формулы. Итак, мы осуществляем первый этап построения теории, вводящий некоторую символику для конструирования логических формул. Логические формулы строятся из символов: f, t — логические константы (значения истинности), Л, #, С, . . ., X, У, Ζ — логические переменные, ( , ) — скобки, \Л &\ 3, 4-» = —двуместные логические операции, ~П — одноместная логическая операция {в дальнейшем для краткости будем слово «логический» иногда опускать). Константа или переменная — это первичная формула. Если Φ — формула, то (Ф) — первичная формула. Если Φ — первичная формула, то Φ — одночлен. Если Φ — одночлен, то |Ф — одночлен. Если Φ — одночлен, то Φ — конъюнкция. Если Фг — конъюнкция, аФ2- одночлен, то Фх& Ф2—конъюнкция. Если Φ — конъюнкция, то Φ — дизъюнкция. Если Фх — дизъюнкция, аФ2- конъюнкция, то Фх\/ Ф2 или "Φι + Фг — дизъюнкции. Если Φ — дизъюнкция, то Φ — импликация. Если Фг — импликация и Ф2 — дизъюнкция, то Фг ZD Ф2 — лмпликация. Если Φ — импликация, то Φ — формула. Если Фх — формула иФ2~ импликация, то Фх == Ф2 — формула. Других формул нет. Эти педантичные определения хороши тем, что они дают совершенно точное определение логических формул, устанавливая одновременно правила старшинства в выполнении логических операций. На языке школьной алгебры можно сказать, что раньше всего выполняются действия в скобках, потом — в порядке перечисления — отрицание конъюнкция дизъюнкция и альтернатива импликация тождество. Автор надеется, что этой апелляции к опыту читателя будет достаточно, чтобы удостовериться, что, например, такой текст
§ 6.1. ЛОГИЧЕСКИЕ ФОРМУЛЫ И БУЛЕВЫ ФУНКЦИИ 193 является правильной формулой, в котором выделение аргументов для каждой операции происходит единственным образом, а именно ((((X & Π Υ)) \JZ)=>n X)) s ((Υ V (Π Ζ) & V)) ζ> Ζ)) э s(y&nx)). Формальный синтаксис. Здесь нам будет уместно несколько отвлечься от основной нити изложения. Дело в том, что только что данное индуктивное определение логических формул основано на общем приеме, который настолько важен в программировании, что не поговорить о нем, имея подходящий повод, было бы непростительно. Сначала заметим, что для таких индуктивных конструкций применяется простая символика, позволяющая сделать определение более компактным и наглядным. Общий смысл индуктивного определения состоял в том, что мы последовательно определяли все более и Орлее широкие классы формул, начиная с «первичных формул», через «одночлены», «конъюнкции», «дизъюнкции» и «импликации»·— к общему понятию «формулы». Кроме этого, мы вводили промежуточные буквенные обозначения Ф, Фх, Ф2, чтобы показать, как конкретно конструируется тот или иной класс формул. Первое правило символики, которую мы сейчас вводим, позволяет вместо буквенных обозначений использовать сами названия строящихся конструкций, заключенные для определенности в угловые скобки. Это позволит вместо фразы «если Фх — импликация и Ф2 — дизъюнкция, то Фх zd Ф2 — импликация» писать короче (импликация):: = (импликация) zd (дизъюнкция) где знак : : = означает «равно по определению». Эта запись, равно как и исходное словесное определение, означает способ задания множества формул, называемых «импликациями» через множество «импликаций» же и множество «дизъюнкций» следующим образом. Надо взять любую «импликацию», приписать к ней знак id, за которым поместить любую «дизъюнкцию». Полученная строчка текста по определению является элементом множества «импликаций». Заметим, что в нашей системе правил нет никакого заколдованного круга, так как для начального множества импликаций есть другое определение, которое гласит «если Φ — дизъюнкция, то Φ — импликация», или — в новой символике — (импликация) :* = (дизъюнкция). Таким образом для импликации мы имеем два "альтернативных определения, которые объединяются вместе с использованием
194 ГЛ. б. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ вертикальной черты, отделяющей в правой части конструкции одну альтернативу от другой: (импликация)» :: = <дизъюнкция> |<импликация> zd (дизъюнкция) Сама конструкция называется металингвистической формулой, а определяемые конструкции — металингвистическими переменными (имея в виду, что их значениями являются элементы конструируемого множества допустимых объектов, в данном случае — логических формул). Все правила для логических формул целиком выглядят следующим образом: <константа> :: = f 11 (переменная) :: = А\В\С . . . \X\Y\Z (первичное) :: = (константа) [(переменная) |((формула>) (одночлен) :: = (первичное) |~1 (одночлен) (конъюнкция) :: = (одночлен) |(конъюнкция)& (одночлен) (дизъюнкция) :: = (конъюнкция) ((дизъюнкция) у (конъюнкция) ((дизъюнкция) + (конъюнкция) (импликация) :: = (дизъюнкция) ((импликация) zd (дизъюнкция) (формула) :: = (импликация)((формула) = (импликация). В такой трактовке правила задания формул напоминают грамматику естественного языка, в которой роль частей речи играют металингвистические переменные. Это сходство не случайно, и в математике часто называют языком любой регулярный способ задания конструктивных объектов, образующих некоторое множество L слов в заданном алфавите. Более точно, языком называют само множество L, а способ задания языка L называют его формальной грамматикой. Строгое описание формальной грамматики само требует некоторой символики, описываемой обычно в каком-то другом языке, называемом метаязыком, используемым для описания языка L. В нашем случае мы описываем язык логических формул, исполь- вуя метаязык металингвистических формул. Список металингвистических формул называют синтаксисом описываемого языка. Понятие формальной грамматики в применении к естественным языкам сложилось наиболее полно в 50-е годы в работах американского лингвиста и математика Н. Хомского. Аппарат металингвистических формул был в 1959 г. предложен американским математиком и программистом Дж. Бэкусом и использован его датским коллегой П. Науром в 1960 г. для описания языка алгол 60. В их честь грамматики, описанные с помощью металингвистических формул, называют БНФ-грамматиками (бэкусово- наурова форма). С тех пор этот аппарат широко применяется для описания языков программирования, а в последние годы перекочевывает и в чисто математические работы.
§ 6.1. ЛОГИЧЕСКИЕ ФОРМУЛЫ^ БУЛЕВЫ ФУНКЦИИ 195 Уточнение способа описания логических формул позволяет нам теперь более точно сказать, что значит, что «выделение аргументов для каждой операции происходит единственным образом». Пусть нам дана какая-то логическая формула. По правилам БНФ-грамматики мы усматриваем, что она или оказывается импликацией, или строится из другой' логической формулы, знака операции = и некоторой импликации. Читатель может проверить, что выбор альтернативы в этом анализе будет производиться однозначно. Эта однозначность является важным свойством удачно составленной БНФ-грамматики. Итак, для каждой логической формулы мы можем построить один из двух таких графов: (формула) или (формула) ц^мплиницця) (срормули) ΓξΛ (шяпликация) При этом мы не только единственным образом выбираем альтернативу, но и однозначно разбиваем текст исходной формулы на части, сопоставляемые нижним металингвистическим переменным. Это означает, что для каждой из выделенных, как говорят, «прямых конституент» исходной формулы мы можем в свою очередь однозначно выбрать составляющие их подформулы, нарастив наш граф снизу еще одним слоем металингвистических; неременных или символов исходного алфавита. Этот процесс «разбора» формулы будет продолжаться, пока по каждому направлению в строящемся графе (он, очевидно, окажется деревом) мы не доберемся до символа исходного алфавита, который станет терминалом дерева. Полученный граф, который оказался построенным однозначно для взятой логической формулы, называется ее деревом разбора. Его вершинами яляются символы исходного алфавита и металингвистические переменные. Для краткости и общности первые называются терминальными, а вторые — нетерминальными символами БНФ-грамматики. \ Дерево разбора для приведенной логической формулы (*) доказано на рис. 6.1. . Булевы функции. Здесь уместно вспомнить, ради чего был разведен этот формализм. Мы ввели логические формулы как средство точного описания сложных высказываний (логических формул),, истинность которых может быть установлена на основе истинности исходных фактов (логических переменных) с использованием
196 ГЛ. β. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ содержательных свойств логических связок (логических операций), веданных своими таблицами истинности. Для того чтобы оправдать наш язык логических формул, мы должны теперь дать им должную интерпретацию, т. е. показать, как получить суждение об истинности или ложности логической формулы, если нам известны значения истинности исходных фактов (логических переменных формулы). \ Рис. 6.1. Дерево разбора логической формулы. С использованием дерева разбора «момент истины» достигается с помощью следующей индуктивной процедуры. Базис индукции: терминальным символам — переменным (логическим константам) заданы (присущи) некоторые значения истинности. Шаги индукции: если нетерминальный символ η имеет единственную конституенту с приписанным ей значением истинности σ, то σ приписывается символу п\ если нетерминальный символ η является одночленом вида ~~}п' и символу п' приписано значение о, том получает значение ~~]σ (по таблице истинности); если нетерминальный символ η является конструкцией вида л'рга", где ρ — одна из логических операций, \/, +,:=>,==, и
§6.1. ЛОГИЧЕСКИЕ ФОРМУЛЫ И БУЛЕВЫ ФУНКЦИИ 197 символам п' и п" приписаны значения ох и σ2 соответственно, то η получает значение огро2 (по таблицам истинности). В конце концов, пройдя все слои дерева разбора, мы припишем его корню, а с ним и всей логической формуле значение истинности. Поскольку дерево разбора строится по формуле однозначно, постольку и само вычисление истинности дает единственный результат. Итак, наша интерпретация логических формул состояла в том, что мы связали с каждой из них единственным образом некоторую функцию какого-то (возможно, и нулевого) числа аргументов, для которой и значениями аргументов, и значениями самой функции являются значения истинности t и f. Подобного рода функции называются логическими функциями, или функциями алгебры логики, или булевыми функциями, по имени английского математика Дж. Буля, их исследовавшего. Для успешного продвижения вперед нам надо будет подробнее познакомиться с этими функциями. Прежде всего мы обнаруживаем, что каждая булева функция может быть задана в виде конечной таблицы истинности. Если зафиксировать порядок перечисления значений аргументов функции (он совпадает с алфавитным следованием от f к t), то каждая функция будет полностью описываться столбцом своих значений. При этом разным столбцам будут соответствовать разные функции. Ниже мы даем список всех булевых функций двух переменных (их всего 16) / 4- & == => V \х,х2 F± F2 Ft F, F& F9 F7 F8 F9 F10 Ftl F12 Fl3 Ры Flb Fl9 oW All f t f t f t f t f t f t f t f t 2 =4 { t f f t t f f t t f f t t f f t t I t f ffffttttffffttt t (t t f f f f f f f f t t t t t t t t Размышление! над этой таблицей позволяет сделать следующие наблюдения: Теорема 1. Булева функция η переменных имеет 2п разных наборов значений ее аргументов. Теорема 2. Всего имеется 22П булевых функций η переменных. Часто удобно представлять значения истинности f и t нулем и единицей соответственно. В этом случае булевы функции становятся арифметическими двоичными функциями. При такой трактовке конъюнкция оказывается простым умножением, альтернатива — сложением по модулю 2, а отрицание — вычитанием из единицы. Вернемся еще раз к табличному представлению булевых функций. Пусть Ω — полное множество наборов значений аргументов
193 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ ' функции п переменных, которые будем считать раз и навсегда как-то упорядоченными. При арифметической трактовке каждый такой набор — это двоичный вектор длины п. Для каждой функции / можно рассмотреть множество наборов Г/, на котором она истинна (множество истинности), и множество F/, на котором она ложна. Очевидно, что Tf\jFf = Ω. Очевидно такще, что если Τ η = Τи, то fx = /2 и, наоборот, если fx = /2, то и Ти = Ти. Это позволяет нам отождествлять булевы функции η переменных с их множествами истинности. Это отождествление позволяет дать интересную1 и полезную трактовку некоторых логических операций. Читатель без труда убедится, что если g и h — булевы, функции одного и того же числа переменных, то имеет место Теорема 3. Если f = g\Jh, mo Tf = Tg[) Th; если f =» g&hmo Г/ = Tg(\Th; если f β ~~|?» m0 Tf — ®\Tg\ если f =■ g zd ft, mo Tf = Ω тогда и только тогда, когда Tg Q Пусть σ — значение истинности. Обозначим Χσ логическую формулу X, если σ = t, и ~~\Х> если σ = f. Пусть ои . · ., оп — произвольный набор η логических значений. Назовем логическую формулу χϊ&χα2*&...&χ°η элементарной конъюнкцией. Она задает F u" n(#lt...,#n) *) — булеву функцию, которая истинна на единственном наборе значений своих аргументов, а именно, когда Х2 = (Т2> • · · · Другими СловаШ* ^σι...σ„={(σ1...ση)>. Очевидно, что если / = FG^*,(yn, a g — FXi'"Jn, где τέ — также значение истинности, то Tfyg - {(σχ,..., ση)} U {(τ,,..., τη)}. Отсюда сразу вытекает очень важная *) Здесь и дальше мы будем различать формальные переменные X (буквы алфавита логических формул) и абстрактные переме шые я? (аргументы булевых функций). Между ними есть очевидное соответствие, но это не одно и то же.
§ 6.1. ЛОГИЧЕСКИЕ ФОРМУЛЫ И БУЛЕВЫ ФУНКЦИИ 199 Теорема 4. Если j(xx, . . ., хп) — булева функция, принимающая хотя бы на одном наборе аргументов значение t, то логическая формула V ΧΪ&Χα2\..&Χ°ηη (σ1...ση)£Γ/ задает функцию f(xl9 . . ., хп). Такая формула, в которой для определенности слагаемые конъюнкции упорядочены в соответствии с фиксированным порядком наборов (Oj . . . ση), называется (дизъюнктивной) совершенной нормальной формой функции /. Нормальной она называется благодаря своему стандартному виду (дизъюнкция конъюнкций), а совершенной — благодаря следующей, также очевидной теореме: Теорема 5. Две булевы функции fug равны тогда и только тогда, когда их совершенные нормальные формы текстуально совпадают. Две последние теоремы непосредственно используют то свойство, что булева функция однозначно представляется своим множеством истинности. Интерпретация логических формул связывает с каждой формулой некоторую булеву функцию. Теоремы 4 и 5 показывают, что даже некоторого меньшего запаса логических формул (совершенных нормальных форм) уже достаточно, чтобы задать любую булеву функцию. Согласно теореме 2 имеется всего 22Л разных булевых функций η переменных. Число же разных логических формул в БНФ-грамматике, использующей η разных переменных, с очевидностью бесконечно. Таким образом, имеется бесконечное количество формул, задающих одну и ту же функцию, или, как мы будем говорить, эквивалентных формул. Сам по себе этот факт вряд ли удивит читателя, однако он требует делового ответа на два вопроса: Как узнать, что две формулы эквивалентны? Можно ли построить алгебру логических формул, т. е. способы систематического преобразования формулы в другие, ей эквивалентные? Не будем тратитьи&лов на обоснование важности этих вопросов, на которые математику в той или иной мере приходится отвечать при разработке любой упорядоченной символики. Отметим только, что в математической логике эти задачи получают свое полное решение, при этом разными методами, которые, как автор уже подчеркивал, моделируют многие более развитые математические теории. Заметим сразу, что на первый вопрос существует по крайней мере один вариант утвердительного ответа, требующий прямой, но громоздкой процедуры4, взяв функции, задаваемые формулами
200 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ и перебирая по очереди все наборы значений аргументов, вычислить на этих наборах значения функций, составить таблицы истинности и сравнить. Примем к сведению эту возможность, а пока приступим ко второму вопросу. § 6.2. Алгебра логики Система тождеств. Читатель, несомненно, достаточно подготовлен, чтобы понимать, что основным инструментом равносильных преобразований, т. е. преобразований, сохраняющих эквивалентность, являются тождественные соотношения между формулами. Уже наш школьный багаж содержит большой запас тождеств для арифметических операций: а + Ь== Ъ + а, а(Ь + с) = ab + асг a(bc) = (ab)c, алгебраических тождеств: (а + ь)2 = а2 + 2аЪ + Ъ\ (а2 _ ь«) = (а + Ъ){а - Ь), тригонометрических соотношений: sin2 χ + cos2 x = 1, sin (а + b) = sin α-cos b + cos a*sin b и т. п. Непосредственное рассмотрение простейших логических формул и основных логических операций позволяет найти немало важных соотношений, отражающих свойства булевых функций. Одни из них тривиальны, а другие выглядят неожиданно и интересно, и их обнаружение в свое время вносило существенный вклад в развитие логики *). Первая группа соотношений выражает, так сказать, внутренние свойства логических операций ΠΊ* = *. (1) х\1 У = У\/ х, (2) *V(»V*) = (*V0)V*> (3) х&у = у&х, (4) z&(y&z) = (x&y)&z, (5) *) В последующем изложении мы оставим в стороне сравнительно реже употребляемую операцию альтернативы \ (исключающее «или»).
§ Ъ$. АЛГЕБРА ЛОГИКИ 201 X ZD (у =Э Ζ) = у ZD (х ZD Z)9 (6) V = У = У = х, (7) x={y = z) = (x = y)E=z. (8) Заметим, что импликация не обладает ни коммутативностью, ни ассоциативностью. Следующая группа соотношений демонстрирует некоторые комбинированные свойства операций: х&(у V z) = x&y \J x&z. (9) Интересно заметить, что конъюнкция и дизъюнкция взаимно дистрибутивны: х V (у & ζ) = (х V у) & (х V *). (10) Импликация также -взаимно дистрибутивна с дизъюнкцией: χ id (у V ζ) = (χ :=> у) V (х => ζ)9 (11) χ V (У 3 ζ) = (* V 0) => (* V ζ), (12) (^V.!/)32 = (^D2)V(l/3 2), (13) однако для импликации и конъюнкции имеет место только одна дистрибутивность χ zd (у & ζ) = (χ zd у) & (# id ζ). (14) ж=^1ж ="Ί»· (15) Следующая группа соотношений раскрывает свойства операций при наложении некоторых связей на их аргументы: χ γ χ = sf *V ~Ί* = *, a; γ f = χ9 aj\/t = t, Λ: & X = ЯГ, #& ~~|я ='» 2&f = f, #& t = #, яг zd# = t, a: zd (y =d яг) = t, tZDX = X9 tZDX= t, a: zd t = t, (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28)
202 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ s:Df = ~~K (29) χ = χ = t, (30) t = x = x, (31) Ιξϊ = 1ϊ. (32) Последняя группа соотношений выражает одни операции через другие: *ν» = ΗΟ&Π»). (33) χ V У = {х => */) => У, (34) *&0 = ΠΠ*ν"ΊιΟ', (35) *Ζ30=-Π»=>Π*, (36) *=>ι/ = ->ν*Λ (37) х=>У = 1(*&1у), (38) ir = » = (a;D|f)&(yDi). (39) Каким бы внушительным этот перечень тождеств ни казался, он оставит критического читателя неудовлетворенным из-за своей произвольности. Действительно, этот список в равной степени легко как пополнить, так и сократить. Например, добавить такое интересное тождество, как X => (у ZD Ъ) = (X ZD у) ZD (X => Z), или исключить, скажем, тождество *=>» = Н(*&~~1у). потому что оно с легкостью выводится из соотношений XZDy = ~]x\/ у, "Т]~~]а: = х. Возникают также вопросы и с менее очевидным ответом: например, выводится ли из этих 39 соотношений такое тождество, как "If = t? Таким образом, найдя какую-то систему равносильных преобразований, мы постоянно должны спрашивать себя, достаточна ли эта система, чтобы в ней вывести любую формулу, эквивалентную данной, и нет ли в этой системе лишних соотношений, т. е. выводимых из других соотношений системы. Конечно, «лишними» мы их полагаем только в теоретическом смысле, так как оказавшись выводимыми из других, базовых соотношений, они остаются сами по себе весьма полезными.
§ 6.2. АЛГЕБРА ЛОГИКИ 203 . Возвращаясь к нашим задачам о выяснении эквивалентности и нахождении алгебры логических формул, мы можем наперед заметить, что если бы мы нашли полную систему тождеств в логических формулах, то получили бы еще один способ распознавания эквивалентности. Действительно, пусть А и В — две логические формулы, задающие булевы функции /А и /в. Для /а и /в существуют их совершенные нормальны^ формы К(/А) и К(/в). По построению А эквивалентна К(/А) и В эквивалентна К(/в). Поскольку наша система тождеств полна, мы можем систематически «вывести» К(/А) из А и К(/в) из В. Если в результате этих двух выводов получатся одинаковые совершенные нормальные формы, то это вначит, что А и В эквивалентны (в силу теоремы 5). Схемы формул. Поставим теперь точно задачу нахождения алгебры логических формул. Добавим к алфавиту языка логических формул буквы Л, В, С, . . ., обозначающие метапеременные. Значениями метапеременных являются логические формулы. Применяя к расширенному алфавиту переменных правила формальной грамматики, мы получим, кроме обычных логических формул, еще и такие формулы, в которых фигурируют метапеременные. Каждую такую формулу мы для отличия будем называть схемой (логической формулы). Схема обозначает не одну формулу, а множество (как правило, даже бесконечное) формул, которые получаются в результате замены каждой метапеременной во всех ее вхождениях на любое (но одно и то же) ее значение. Использование схем вместо конкретных конструкций является обычным математическим приемом формулирования общих утверждений: говоря, что схема обладает некоторым свойством, мы тем самым делаем общее утверждение обо всех получаемых из нее конкретных конструкциях. Конструкция С получается из схемы 5, если существуют значения метапеременных из 5, такие, что при их замене на эти значения S превращается в С. Например, говоря, что схема А \/ ~~\А является тождественно истинной, мы на самом деле высказываем общее суждение о бесконечном списке- формул вида ((А V В) => С) V Π ЦА V В) => С), *-μν~]~Μ, ит. Дм , состоящее в том, что все подобного рода формулы задают тождественно истинную функцию. В ряде случаев, говоря о схемах, мы фиксируем ограничения, налагаемые на метапеременные.
ГЛ. β. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ Например, сделанное утверждение о схеме A \J ~~\A справедливо только, если А — это одночлен *). Уточним далее, что мы имеем в виду, когда говорим, что логическая формула задает булеву функцию. Пусть дано несколько логических формул Фх, Ф2,. . ., Φίβ Зададимся любым количеством логических переменных х1ч . . ., хп, лишь бы их было не меньше, чем разных переменных в этих формулах, и сопоставим каждой переменной из формул одну из логических переменных хг. Это сделано для того, чтобы мы формально могли бы считать в равносильном преобразовании, например, X ZD (у ZD x) = t стоящую справа тождественно истинную величину t функцией двух переменных, χ и у. После такого сопоставления определим, как это было сделано выше, индуктивный процесс вычисления значений истинности как функции ft переменных хх, . . ., хп для каждой из формул Ф^. Полученные булевы функции fu . . ,,ft называются (совместной) интерпретацией формул Ф1э . . ., Ф^. Понятие исчисления. Назовем равносильностью слово вида А- В, где А и В—логические формулы. Равносильность называется тождественной, а формулы — эквивалентными друг другу, если в любой совместной интерпретации соответствующие булевы функции /а и /в тождественно равны друг другу. Допуская вместо логических формул их схемы, получим схему равносильности, для которой уже объясненным выше способом также можно определить свойство тождественности. Заменив в тождествах (1)—(39) знак равенства (который мы зарезервировали для содержательного использования) на —, мы,очевидно, получим серию тождественных равносильностей. Для того чтобы обобщить эти равносильности до схем, нужно заменить символы х, у и ζ на метапеременные, например, А, В и С, и для каждой схемы указать, какие формулы допустимы в качестве их значений. Например, равносильность (34) x\/y={xZDy)ZDy переходит в схему A\j B~{AzdB)zdB, где А и В — конъюнкции. *) На всякий случай предупредим читателя, чтобы он не смешивал только что введенные метапеременные Л, В, С с обозначениями произвольных, но фиксированных формул вида А, В и т. п., неформально используемыми в тексте. Они тоже являются своего рода метапеременными, но в другом метаязыке, каковым является русский язык, на котором написана эта книга.
§ 6.2. АЛГЕБРА ЛОГИКИ 205 Назовем, далее, правилом вывода составную конструкцию, имеющую две части — посылку и заключение: посылка — это совокупность схем логических формул и равносильностей, заключение — равносильность или схема равносильности *). Текстуально правило вывода выглядит как дробь, в числителе которой пишется посылка, а в знаменателе — заключение, например, Χ=>Υ ~~\(Х& 17)J Исчислением называется некоторый список правил вывода и равносильностей (или их схем). Последние в качестве составной части исчисления называются аксиомами {схемами аксиом). Дадим теперь важное индуктивное определение. Некоторая равносильность или схема равносильности R называется выводимой в исчислении Т, если она: 1) или получается из выводимой в Τ схемы равносильности; 2) или является аксиомой в Т; 3) или получается из схемы аксиомы в Т; 4) или, если в Τ есть правило вывода, для которого существуют такие выводимые посылки, которые задают R в качестве заключения этого правила. Это определение раскрывает смысл исчисления, которое является одним из самых фундаментальных математических понятий. В общем случае исчисление — это механизм систематического получения некоторого множества конструктивных объектов путем отправления от некоторого изначального, заданного множества. Этим изначальным множеством являются аксиомы. Каждое правило вывода — это некоторое индуктивное определение новой конструкции (заключения) через конструкции, заданные в его посылке. Для каждой конструкции, выводимой в исчислении, можно указать историю ее вывода, отправляясь от аксиом. В своем наглядном представлении эта история имеет вид дерева, терминалами которого являются аксиомы, а остальные вершины — это заключения правил вывода; при этом входные дуги такой вершины указывают на источник посылок, а выходная дуга указывает на место использования заключения в качестве посылки следующего правила. Такое дерево называется деревом вывода конструкции в исчислении. Исчисление само по себе, однако, не наполняет выводимые в нем конструкции каким бы то ни было смыслом. Для этого нам потребуются еще некоторые определения. *) Пусть читателя не смущает, что в пределах одной главы мы используем слова «посылка» и «заключение» как для аргументов импликации, тан л для составных частей правила вывода. Это единство терминологии не случайно.
206 ГЛ. β. КРАТКОЕ ПОВТОРЕДИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ Исчисление равносильностей называется корректным, если любая выводимая в нем равносильность оказывается тождественной. Исчисление называется полным, если любая тождественная равносильность выводима в нем. Аксиомы и правила вывода полного исчисления называются независимыми, если устранение любого одного из них делает исчисление неполным. Исчисление равносильностей. Теперь мы можем сказать, что /вадача построения алгебры логических формул — это задача нахождения корректного и полного исчисления равносильностей» состоящего из независимых аксиом и правил вывода. Введем для краткости еще несколько обозначений. Назовем одночлен, конъюнкцию, дизъюнкцию, импликацию и формулу соответственно формулами первого (высшего), второго, третьего, четвертого и пятого приоритетов. Аналогично операции &,V, => и is получают номера приоритетов со второго по пятый. Буквы Ϋη и рп означают соответственно формулу и операцию тг-го приоритета. ^F< ЗГх'У —; формула £F, в которой выделено одно вхождение подформулы έΓχ тг-го приоритета. ^{ХУ — формула, в которой выделены все вхождения переменной X. Исчисление равносильностей алгебры логики {исчисление Т) Аксиомы и схемы аксиом А1) 1 t ~ f, отрицание, А2) 1 ""] X ~ X двойное отрицание, A3) X\/Y~ Y\/X коммутативность, А4) X\JY\IZ ~ X\/{Y\IZ) ассоциативность, А5) X\JX ~ X поглощение, А6) Χ\/Ί X ~ t исключенное третье, А7) X\/l ~ X дизъюнкция с ложным, А8) ~] (X\JY) ~ Ί Χ&~\ Υ дистрибутивность отрицания А9) X&(Y\/Z) ~ X&Y\JX&Z дистрибутивность конъюнкции, А10) X =э Υ ~ ~] X\/Y импликация, АН) χ=γ~(Χ zd Υ)&(У zd X) эквивалентность, А12) (Fn)p"X ~FnpnX лишние скобки левого операнда, лишние скобки 1^=2 3 4 5 А13) Хрп(Рп-*) -~ XpnFn-i правого операнда-! ' ' ' лишние скобки А14) (F) ~ F формулы.
§6 2. АЛГЕБРА ЛОГИКИ 207 Правила вывода <X>~er2<X>,F3*) <(F3)> - ЗГ2 <(F3)> in) _ g~(m)t ^ <^-(in)> _ ^r4? m < η П/|ч ^j <λ:> — er2 <x>, f3*) „ Ш) *,,, v4—L ,/p 4v ' правило замены переменной, П2а) П2б) ^"я <^"(2W)> ~ #~4 правило равносильной У<"> ~ gf>, gr3 <^(n)> „ y<f w > „ подстановки. ' ^з <(^(2W))> - ^« Корректность данного исчисления устанавливается без труда. Схемы аксиом А12 — А14 позволяют в преобразованиях убирать лишние скобки. Язык логических формул приемлет формулы вида, например, ((А\/ В)) или же (А & В) = С. У нас нет другой возможности, кроме как, введя специальные аксиомы, утверждать такие очевидные тождества, как ((A\JB))~-A\'B, (А&В) = С~~А&В=С. Формула F3, подставляемая на место переменной X в правиле Ш, должна заведомо вычисляться раньше выполнения операций из ЗГг и <F2, по отношению к которым X была операндом. Для этого F3 заключается в скобки, гарантируя наивысший приоритет. При этом, естественно, могут вноситься и лишние скобки, нр это будет «замечено» аксиомами А12 и А13. Условие на приоритеты в правиле П2 также гарантирует, что приоритет формулы, ставшей на место iFin\ будет не больше тг, так что дерево разбора формулы #"3 не будет испорчено. Заметим, что, создавая «инструмент» для тождественных преобразований логических формул, исчисление играет еще одну роль, весьма важную саму по себе. Каждая аксиома, каждое правило Бывода опираются на некоторое свойство формул или функций, задаваемых формулами. Выполняя преобразование, описываемое аксиомой или правилом вывода, мы можем четко сознавать, какое свойство формулы или функции использовано. Способность исчислений фиксировать, или, как еще говорят, постулировать, формализовать те или иные свойства абстрактных объектов (в данном случае — булевых функций) объясняет их центральное положение в математических методах рассуждения. По существу, каждая математическая дисциплина, базирующаяся па аксиоматическом методе, в своем строгом изложении есть не что иное, *) Мы различаем метапеременныеР, значениями которых могут быть любые формулы, и метапеременные^", значениями которых могут быть только такие формулы, которые образуют выводимые равносильности, используемые в качестве посылки правила вывода.
203 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ДОГИКИ как исчисление со своим языком конструкций, изображающих или обозначающих абстрактные объекты аксиом, постулирующих свойства объектов, и правил вывода, позволяющих строить цепочки рассуждений. Само исчисление тоже описывается в некотором метаязыке, который даже если не вводится явно, логически тем не менее в каждой математической работе присутствует. Такие свойства исчисления как корректность, полнота и независимость являются не только его, так сказать, «деловыми характеристиками», но отражают адекватность, законченность и неизбыточность теории, формализуемой данным исчислением. Полнота исчисления равносильностей. Продолжим рассмотрение исчисления равносильностей. Сначала покажем, что задаваемое исчислением отношение равносильности обладает стандартными свойствами отношений эквивалентности. Равносильности Ρ 1) F—F —рефлексивность, Р2) %г 2г симметричность, РЗ) —-—car L сг ~~~ транзитивность. Деревья вывода этих свойств показаны на рис. 6.2 (выделяемые вхождения подформул и переменных подчеркнуты). Замвх^им, что деревья для правил вывода (случаи б) и в)) представляют условный выводу в котором терминалами являются не аксиомы, а равносильности или формулы, образующие посылку доказываемого правила. На рис. 6.2, в) показан сокращенный вывод, в котором вместо поддерева вывода iF2 ~ !Fi из ^х ~ <F2 помещена обозначающая его «метавершина». Доказанные свойства отношения равносильности позволяют выводить целые цепочки эквивалентных преобразований. Теорема 6. Пусть F — логическая формула, переменные которой принадлежат множеству логических переменных {Хх, . . . • . ., Хп}. Тогда выводима одна из двух равносильностей F ~ К (Хи . . ., Хп) или F~f, где К(Х1? . . ., Хп) — дизъюнктивная совершенная нормальная форма. Прежде чем доказывать теорему, заметим, что в силу корректности исчисления и теоремы 5 формула К(ХХ, . . ., Хп) находится единственным образом и является дизъюнктивной совершенной нормальной формой функции, вадаваемой формулой F. Полное доказательство теоремы б слишком громоздко, и мы лишь наметим этапы преобразования F в К, сопроводив их при-
§6 2. АЛГЕБРА ЛОГИКИ 20» мером. В примере мы используем более компактные обозначения для конъюнкции (ΧχΧι — без знака операции) и для отрицания (X). Пусть F = (X, == ХгуХв). Сначала Ρ приводится к форме, содержащей только переменные, дизъюнкции, конъюнкции и отрицания. Эквивалентность / ψ ψ Ι (Λ5) (А5) \ Х*Х~Х Х*Х~Х \ \ ΧνΧ~Χ ΧνΧ~Χ \ УЩ/ / (П1 F~F а) РиС. 6.2. Деревья вывода в исчислении равносильностей. с) Р1: рефлексивность, б) Р2: симметричность, в) РЗ: транзитивность (подчеркнуть выделяемые вхождения формул и переменных). устраняется по All, импликация — по А10, константа f — с помощью А1 и А7. XxS3 Х2\Дз~ (Хх=> Χ2\/Χ3)(Χ^Ύ3^ Хх) ~ ~ ( 1Гл/(ВД*з))П (X,V*i)V*i)~ По аксиоме А8 отрицание, стоящее перед скобками, распределяется по слагаемым дизъюнкции. Если в скобках — конъюнкция,, она также по А8 заменяется на дизъюнкцию. Двойные отрицания, убираются по А2: ~ (ХгУХЫХЖХгХМХг) ~ После этого раскрываются все скобки по А9. При этом используются свойства конъюнкции XX ~ X и XX ~ f, которые получаются из А5 и А6 с помощью А8 и А2. Если все конъюнкции
210 ГЛ. β. КРАТКОЕ ПОВТОРЕНИЕ'МАТЕМАТИЧЕСКОЙ ЛОГИКИ окажутся равными f, мы получим равносильность F ~ f: ~ХгХгХг\/ Х^Х^ХзУ Χ%Χ2ΧΖ\Ι XXXX\J X%XX\J ΧζΧλ~ ~ΧΧΧ2Χ9\/ ХгХ2\/ ХгХ3~ Для совершенной формы нужно, чтобы все конъюнкции состояли из всех переменных Хх, . . ., Хп. Всюду, где это нужно, дополнительные переменные вводятся домножением конъюнкций на тождественно истинную дизъюнкцию (Х\/Х). При этом используется свойство конъюнкции Xt ~ X (из А7): ~Х1Х2Хз\/ ΧιΧ2Χз\/^1^2^з\/ ^Г^2^3\/ ΧΐΧ<ιΧζ~· «Приведя подобные» по А5 и упорядочив конъюнкции лексикографически с помощью A3, получим дизъюнктивную нормальную «совершенную форму ~ X1X2X3\JXxX2Xz\f ΧχΧ2Χζ\ΙΧχΧϊΧζ·VV Терема 7. Исчисление равносилъностей полно. Действительно, пусть ¥г и F2 — эквивалентные формулы. Это значит, что они задают одну и ту же булеву функцию /. В этом случае по теореме 6 имеют место две выводимые равносильности Ft ~ К, F2 ~ К, „где К — или f или совершенная нормальная форма функции /. В силу симметричности и транзитивности отношения равносильности немедленно получаем, что Fx~ F2.VV § 6.3. Исчисление высказываний Общезначимые формулы. Вернемся назад к обсуждению побудительных мотивов к разработке математической логики. Логическая формула — это символическая, сокращенная и точная запись некоторого суждения,— высказывания,— об исходных фактах — логических переменных, взятых, в определенной взаимосвязи, изображаемой с помощью связок — логических операций. Выяснилось, что истинность или ложность высказывания является однозначной функцией значений истинности исходных •фактов. Алгебра логики — это способы преобразования логических формул, оставляющие неизменным их логическое содержание, т. е. задаваемую ими функцию истинности (булеву функцию).
§ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИЙ 21f Среди логических формул естественно выделяются такие^ которые задают тождественно истинную булеву функцию. Эти формулы называются общезначимыми, тавтологиями, или логическими законам^ Напишем несколько формул подобного рода·, и дадим одновременно их словесное выражение. А\/~"] А: каково бы ни было высказывание А, справедливо^ что А либо истинно, либо ложно; Aid AN/В: из всякого факта А следует он сам, каков бы нис был дополнительный факт В; (Aid В)id (G\/Azd C\/B): каково бы ни было отношение- следования, оно сохраняется при рассмотрении как посылки, так и заключения в дизъюнктивном объединении с любым дополнительным фактом С. Понятие общезначимости подчеркивает тот факт, что задаваемая формулами булева функция сохраняет свое значение истинности на всех значениях аргументов. Понятие тавтологии подчеркивает, что тождественно истинное утверждение является в некотором смысле тривиальным, не дающим никакой информации о взаимосвязи входящих в него высказываний. Действительно, если мы знаем, что А & В истинно, то мы знаем, что и А и В являются истинными утверждениями. Однако же истинность утверждения Агэ А\/В не налагает никаких связей на А и В. Таким образом, общезначимая формула характеризует скорее некоторое* свойство входящих в него логических связок, проявляющее себя безотносительно не только к смысловому содержанию, но даже* и к значениям истинности входящих в нее логических переменных. Эта высшая степень общности подчеркивается употреблением термина «логический закон». Сконцентрировав наше внимание на общезначимых формулах,, мы немедленно усматриваем тесную связь вопроса с равносильными преобразованиями логических формул. Действительно, несделанных определений немедленно вытекает Теорема 8. Пусть Aw В — логические формулы. Равно- сальность А ~ В будет тождественной тогда и только тогда, когда формула Α ξξ В общезначима. Эта теорема наводит нас на мысль, что задача нахождения* системы равносильных преобразований логических формул является лишь частным случаем более общей задачи построения исчисления, позволяющего выводить из некоторых аксиом с помощью* правил вывода все общезначимые формулы, в том числе и те, которые описывают тождественные равносильности. Мы приступим к рассмотрению этой%задачи, опираясь на опыт построения исчисления равносильностей алгебры логики. Шм< уже приходилось мимоходом замечать некоторую пестроту, разноплановость аксиоматики равносильностей. Одни аксиомы отражают скорее свойства способа конструирования формул («скоб-
212 ГЛ. β. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ кология» аксиом А12 — А14), нежели свойства логических операций. Другие аксиомы просто выражают одну операцию через другие (например, АН) или один объект через другой (например, А1). Действительно, А = В общезначима тогда и только тогда, когда общезначима /формула (A=d В) & (Bid А). Любая конъюнкция общезначима тогда и только тогда, когда общезначимы «ее сомножители, в данном случае, Aid В и Bid А. Другими словами, если уметь выводить общезначимые формулы вида A id В и располагать правилом вывода «если выводимы А и В, то выводимо А& В», то все общезначимые формулы, которые можно трактовать как эквивалентности, будут выводимы. Таким образом, в отличив от других логических операций, мы трактуем знак ΞΞ не как фундаментальную логическую связку, смысл которой раскрывается независимыми аксиомами, а как обозначение более ■сложной конструкции, вводимое ради сокращения письма. В этом направлении можно пойти и дальше. В качестве синонима t можно взять, например, формулу X\J ~\ X, a f изображать формулой X & ~"| X, и все мыслимые общезначимые формулы, упоминающие значения истинности, стараться выводить с учетом этой синонимии. Можно, далее, упростить синтаксис логических формул, отказавшись от формализации старшинства двуместных операций: (переменная) :: = А\В\С\ . . . \X\Y\Z <первичное> :: = <переменная>1"|< операнд) (операнд) :: = (первичное>|(<(двучлен5) (двуместная операция) :: = Vl&I13 <двучлен> :: = (операнд)(двуместная операция) (операнд) <формула> :: =» (первичное)>|(двучлен) Опять-таки, мы можем по соглашению опускать скобки в формулах, но это уже будет содержательное сокращение для удобства написания и чтения, а не правило формальной теории. Повсеместное использование схем аксиом позволит избавиться от правила вывода, разрешающего замену переменных и подстановку. Исчисление высказываний. После сделанного предисловия мы продемонстрируем исчисление общезначимых логических формул {исчисление L), близкое к описанному американским математиком С. Клини в 1952 г. Исчисление высказываний (исчисление L) Схемы аксиом А1) Aid (Bzd А) А2) (Л =}(#=> C))zd ((AzdB)zd (A id С)) A3) (А & В) id A А4) (А & B)zd В
§ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИИ 213 А5) Azd(Bzd(A& В)) А6) Azd(A V В) ΑΙ) В id (A \/ В) А8) (AzdC)zd ((В zdC)zd ((А \/ В) => С)) А9) (П4з -\B)iD (CIAzd B)zd A), Правило вывода Исчисление высказываний корректно, если любая выводимая формула оказывается обЬ^значимой, и полно, если любая общезначимая формула выводима в этом исчислении. Для исчисления высказываний важным является еще одно свойство — непротиворечивость, τ· θ· несуществование такой формулы А, чтобы в исчислении выводились как А, так и ~~\А. Понятие непротиворечивости позволяет по-другому сформулировать свойство полноты: исчисление высказываний является полным (в узком смысле), если добавление к нему хотя бы одной невыводимой из него формулы в качестве аксиомы делает расширенное исчисление противоречивым. Описанное исчисление L корректно и полно, непротиворечиво и полно в узком смысле. Свойства непротиворечивости и полноты в узком смысле интересны тем, что они определяются в терминах самого исчисления, не требуя интерпретации формул как конструкций, задающих функции истинности. В то же время эти свойства (по крайней мере для исчисления L) в точности соответствуют свойствам корректности и полноты, использующим понятие общезначимости. Способность исчисления высказываний характеризовать свои полезные свойства, не используя интерпретацию, основанную на понятиях истинности и ложности, а опираясь только на понятие противоречия, понимаемого к тому же чисто формально, явлдется своеобразной чертой логики высказываний, не столь частой для формальных теорий *). Поясним аксиоматику исчисления L. В этих неформальных пояснениях мы будем трактовать высказывания как события, влекущие одно другое. Аксиома А1 постулирует, что наличное событие может быть признано следствием любого другого события («истина следует из всего»). Аксиома А2 подтверждает > что если ^УЩествУет цепная дву- ввенная зависимость событий и наличествует первое звено цепоч- *) Позволяя себе некоторую вольность в аналогия^ можно заметить, что эта «необязательность» интерпретации логических высказываний как носителей истинности или ложности отражает бытующее мнение, что для фор· шального логического рассуждения на первом мест· стоит именно его непротиворечивость суждений, а не «правильность» заключительного вывода.
214 ГЛ. β. КРАТКОЕ ПОВТОРЕЦИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ ки, то допустимо считать, что исходное событие влечет заключительное. Аксиомы A3 и А4 постулируют, что наличие совместного события влечет наличие каждого из его составляющих событий. Аксиома А5 постулирует, что последовательное наступление двух событий влечет наступление совместного события. Аксиомы А6 и А7 показывают, что наступление любого из двух событий вызывается либо одним, либо другим событием. Аксиома А8 гласит, что если каждое из двух событий влечет третье, то для гарантии его наступления нам достаточно знать, что имело место любое из них. Аксиома А9 постулирует метод доказательства от противного: если посылка влечет как заключение, так и его отрицание, то посылка неверна. Правило Ш — это хорошо известное в логике правило заключения: если известно, что при заходе солнца наступает ночь, и известно, что солнце зашло, то справедливо заключить, что ночь наступила. Свойства исчисления высказываний. Корректность исчисления L устанавливается очень просто с использованием таблиц истинности. Доказательство остальных свойств требует целой серии промежуточных утверждений, большинство из которых имеют самостоятельное значение в качестве правил логического вывода. Говоря об исчислении Т, мы уже употребляли понятие «условного вывода», используемого как доказательство некоторого производного правила вывода.Условный вывод—это дерево вывода, корнем которого является выводимая конструкция, а среди терминалов могут быть как аксиомы, так и вхождения произвольных формул, играющих роль посылок. Для сокращенной записи утверждений о существовании условного вывода формулы (схемы формулы) В из множества посылок {Ах, . . ., Ап} употребляется «знак выводимости»!—, с помощью которого утверждение об условной выводимости записывается в виде так называемой секвенции Aj, . . ., Απ(— В. Запись (—В означает утверждение о (безусловной) выводимости В. Условную выводимость В из посылок Aj,. . . . . ., Ап называют просто выводимостью В из Ах, . . ., Ап. Разрешается, чтобы реальное дерево вывода В из посылок Ах, . . ., Ад содержало бы в качестве терминальных вершин вхождения из любого подмножества из {А1? . . ., Ад}. Правияа логического вывода Т1: Если А19 . . ., Ап_г, Ап |— В, то А^, · ·.., An_! I AnZ3 Ъ.
§ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИЙ 215 Другое обозначение: ν...,ΑηΗΑΛ3Β ' Т2:Л, AzdB\~B, ТА: А, Ву-А&В, Т4 : А & В μ А, Ί5:Α&Β\-Β, Т6: А\-А \J В, Т7 : β f- A V В, A! АЯ,1ВЮ,А, АВЛВЦС Αι AftJB T10: 11 Л h ^· Правило Т1 называется теоремой о дедукции. В сочетании с Т2, которое, являясь правилом вывода Ш, помещено в этот перечень для полноты, эта теорема объясняет точный логический смысл импликации как эквивалента выводимости: \— Azd В тогда и только тогда, когда А (— В. Остальные правила, опираясь на эту эквивалентность, являются перефразировками и простыми обобщениями аксиом из исчисления L. Доказательство теоремы о дедукции Лемма Л1 :\- AzdA. Доказательство 1. \-Azd (Л :э А) по А1 при В = А, 2. f- (А =э ((A zd A) zd Л))=э ((Л=> (Л:э Л))=> (Лгэ A)) по А2 при β = Aid Л, С = Л, 3. h(4:D (^=> ^))=> (4=э Л) по Ш с ^ из А1 при β =» е=ЛэЛи^э^изп 2. 4. |— Л id Л по Ш с ^ из п. 1 и ^ zd i5f из п. 3. ν Пусть формула В выводится из формул Ах, . . ., Ап. Распределим формулы, образующие дерево условного вывода, по ярусам. В первый ярус попадут все терминальные вершины. В ΐ-й ярус попадают вершины, имеющие среди предшественников хотя бы одну вершину (i — 1)-го яруса. Теорема будет доказана индукцией по числу ярусов в дереве вывода. В первом ярусе находятся либо выводимые формулы (аксиомы), либо формулы из списка Аъ . . ., Ап. Докажем, что любая
216 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ формула В из 1-го яруса удовлетворяет теореме. Если В—выводимая формула, то,взяв в ГЦ в качестве посылок В и B=d (AnZD zd В), получим в качестве заключения f— AniD В. Если В = Anf то по лемме Л1 получаем |—AniD An. Если В = А^ (ί<η), то, взяв по аксиоме А1 выводимую формулу A^id (AniD A^) и А|В качестве посылок правила Ш, получим, что А* |— AniD Af. По определению условной выводимости получаем, что для фор· мул В первого яруса справедливо Ах, . . ., Ап_х |— Ап:э В. h-Λ,,Β > χ γ γ (дд) Φ ν—mi) А},..Л,С ^^о-Л) Υ Аь-А. (£) ^P (-iA=>iiA)=((-]A=>iA)=A) ΊΑ=^Α 4^ (iA=>-nA)=>A .a). Φ РиС. 6.3. Деревья вывода в исчислении высказываний. Л^.-.Ип, ВУ-D, Аи..., An, C\-Dt а) Метатеорема Т8: —* ^ Ап B\/C\-D б^ СеквенДИЯ Т10: "1 А |— Л. а: обозначение условного вывода, β: применение метате- оремы, у: посылка условного вывода, δ: подстановка в схему аксиомы. Рассмотрим любую формулу В из i-ro яруса и допустим справедливость теоремы для любой формулы из ярусов с меньшими номерами. Формула В получается применением правила Ш к посылкам А и Ad В, для которых по индуктивному допущению как AnZD А, так и AnD (Ad В) выводимы из Alf . . ., Ап-Х. Взяв в аксиоме Л2Ап = 4,А = ВиВ = С получим выводимую формулу (Апid (Aid B))=d ((AniD A)id (AniD В)). Взяв эту формулу в качестве si =d Jf и AniD (Aid В) в качестве s£ в Ш,v
§ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИЙ 217 получим Alt . . ., An_xI— (AniD А)=э (An=D В). Взяв снова в Ш формулу (AniD A)=d (Auzd В) в качестве j^zd & и Ап = А в качестве^, получим заключение А1? * · ., An-11— Auzd В. Теоре* ма о дедукции доказана^V Теорема о дедукции, а также правила Т8 и Т9, являют собой примеры таких утверждений о выводимости, которые доказываются не только записью формального вывода в исчислении, но и некоторым общим и неформальным рассуждением о той или иной выводимости без ее конкретного изображения. Этот «второй» слой логического рассуждения приводит к тому, что подобного рода утверждения называют метатеоремами. На рис. 6.3 изображено дерево условного вывода метатеоремы Т8 (принцип доказательства разбором случаев) и секвенции Т10 (снятие двойного отрицания). Построенные правила вывода позволяют сблизить аксиоматику исчисления высказываний с правилами равносильных преобразований логических формул. Понимая сокращенную запись (А) === (В) как схему формулы ((A)zd (В)) & ((B)zd (А)), мы можем сформулировать / в исчислении известные свойства операции тождества, а также связь выводимости с общезначимостью. ТИ: \-А = А, Т12: A = B}-B==Af Т13: А = В, В=вС\-А = Су Т14: A, A = B\-Bt τΐ5.:μ^ νπ^· Для Т13 требуется очевидная лемма о транзитивности импликации. Л2: A zd В, В zdC\^Azd C% которая, хотя и содержится неявно в аксиоме А2, получается не сразу из нее, а с помощью теоремы о дедукции: из трех посылок Л, А чэ В, BDCc помощью двукратного применения #1 выводится С, после чего по теореме о дедукции получаем условную выводимость A zd С. Рис. 6.4 показывает вывод Т15 (закон исключенного третьего). В отличие от исчисления равносильностей логических функций, правило подстановки в исчислении высказываний не аксиоматизируется (правило П2 в Т), а доказывается в виде так называемой «теоремы о замене». Теорема 9. Пусть С (А) — формула, β которой выделено вхождение формулы Α, α С (В) — формула, которая получается
218 ГЛ. б. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ из С (А) заменой вхождения А на В. Тогда А = В ί- С (А) = С (В). Доказательство. Рассмотрим дерево разбора формулы С (А) в языке логических формул исчисления L. Назовем глубиной d вхождения А в С число дуг в пути от вершины формулы А к корню дерева разбора формулы С и проведем рассуждение индукцией по d. Ί(ΑνιΑ) τνΐ -ι{ΑνιΑ) ~ιΑ I i{A\nA)=>bA=>i(AviA)) Ί(ΑνιΑ) -\ίΑ i{AviAM-nA=i(AviA)) 4S>Y \ny^ Α ΑνιΑ γ A=(AyA) ■vMtfv-Ц) /W\ τΗ=(4ντΗ) Λ ч4 \(т4=1(/1упИ)МЫ=(^пД)>,4) (m ί4 AnA ¥\(τιϋ=Ί(4ντ4ί=ΦνΗ4ντ4Ϊ3τ4) ^ Ϊ11) /АчтА А А I— 4gb-v (η(4ντ4)=»4)=>(4ντ4) (ΠΙ) ΗντΛ Рис. 6.4. Вывод закона исключенного третьего. Базис индукции. При й = 0С(А) = АиС (В)= В, так что утверждение теоремы имеет вид AsBhA^B, что справедливо по свойствам условного вывода. Шаг индукции. Пусть глубина вхождений А в С равна d + 1. В соответствии с синтаксисом языка логических формул
§ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИЙ 219 β В~А A A?ff П1) т) V №Μ=Λ) ОМ) A CM) V L-foJj S(A^)l(i {(A=C)=>(S=>C))k№H№)) a) С АСмВ С 8 CsiA (P\tA)Hftff) м©-у 4m/ φν0)=>ψνΑ) ψ Φ Рис. 6.5. Вывод лемм из теоремы о замене. a)A = B[-AzDC = BzDC. б) 4 = В Η С V 4 = С V В.
220 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ С (А) имеет одну из следующих форм: C(A) = (M(A))Z)(N), (Ν) Ζ) (Μ (А)), (Μ(Α))&(Ν), (Ν)&(Μ(Α)), (M(A))V(N), (N)V(M(A)), Π Μ (A); при этом глубина вхождения А в Μ (А) равна d, а, стало быть, по предположению индукции имеет место секвенция: А = В Ь Μ (А) == Μ (В). Сформулируем следующие Леммы: ЛЗ: А = В μ А=>С === В=эСг Л4: А = В\- CzdA = CzdB, Л5: А = В\-А&С = В&СГ Л6: А = В[-С&А = С&В, Л7: А = В Η А V С = В V С% Ж: A~B[-C\I A = C \J В% Л9: А = В |- Π 4 г П^· Для примера доказательства нескольких из них даны на рис. 6.5. После этого проведем для каждой из синтаксических форм для С (А) рассуждение по следующей схеме. Пусть C(A)=M(A)pN. По предположению индукции А = В Ь Μ (A) S Μ (В). По соответствующей лемме имеем Μ (Α) = Μ (Β) Η Μ (Α)ρΝ г Μ (Β)ρΝ, что в силу транзитивности свойства выводимости дает А == В [— (— С (А) = С (В), что и требовалось доказать. V V Включение в исчисление знака тождества и обоснование его свойств позволяет доказать в исчислении в виде выводимых схем формул все тождественные равенства булевых функций (1)—(39) (с использованием формул вида В\/ | В и В &П В вместо t и f соответственно). Большая часть выводимостей получается прямым применением подходящих аксиом и правил вывода Т1 — Т10д
§ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИЙ 221 однако некоторые выводы достаточно длинны: пример доказательства дистрибутивного свойства конъюнкции но отношению к дизъюнкции дан на рис. 6.6. А В А С Л- А&С. АиВ У. Ш АиС А&В tie AiC {A6cB)m{AScO А,ВчС Awe) I—(g>A7 АлКВыС) λ (Π1 Α γ Α \ Bvff (Α&φνΙ$={(Α&Β)ν(Αά(Τ>) (lAScB)\i(AbC))=>№B\tC)) (Aic{fls/C))={AScB)\i{AbCD Рис. 6.6. Вывод дистрибутивности конъюнкции относительно дизъюнкции. Полнота, непротиворечивость и независимость. Наше изучение исчисления высказываний подходит к концу. Наметим доказательство полноты исчисления L. Пусть дана общезначимая формула А. С помощью цепочки тождественных преобразований с использованием теоремы о замене мы получим выводимость ЬА^КА, где Ка — совершенная нормальная дизъюнктивная форма. Поскольку А общезначима, КА должна содержать полный набор элементарных конъюнкций, который очень просто с помощью тождественных преобразований представить в форме (Хх ν Π Χι)&·. · &(Хп V Π Χη),
222 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ что в свою очередь преобразуется в выводимую формулу вида В V Π В. По Т15 имеем (-- В V "1 В» откуда по Т14 получаем выводимость А. Непротиворечивость вытекает из корректности и из того, что отрицание любой общезначимой формулы есть формула необщезначимая. Полнота в узком смысле устанавливается следующим рассуждением. Пусть А — невыводимая в исчислении L формула. В силу полноты L А не общезначима. Пусть Xl9 . . ., Хп — переменные в формуле А и ои . . ., ση — набор значений, на которых интерпретация А имеет значение f. Заменим в А все вхождения переменной Xt формулой X V "П %> если Oj = *> и "Л (-Х. V Π Χ)* если Οι = f. В результате мы получим формулу А', которая, оставаясь невыводимой в L *), имеет к тому же тождественно ложную интерпретацию. Но тогда в L будет выводима ~~] А'. Включим теперь В в качестве схемы аксиомы в L, заменив ее переменные на метапеременные. Получим исчисление L', в котором будет выводима формула А. Поскольку правила подстановки формул на место переменных в I/ сохраняют силу, формула А' также окажется выводимой в Ъ'9 что приводит к противоречию с выводимостью Ή А'в I/. Точное доказательство полноты в узком •смысле требует следующей теоремы. Теорема 10 (о подстановке). Пусть А(Х) — формула со #семи выделенными вхождениями переменной X и А (В) — форму* ла9 полученная подстановкой формулы В во все вхождения X. Тогда, если f- А (X), то [—Д (В). Доказательство. Рассмотрим дерево вывода D формулы А (X) и выделим все вхождения переменной X во все терминальные формулы. Каждая из этих формул представляет собой аксиому, содержащую метапеременные М19 . . ., Mkf замененные на какие-то их фиксированные значения (^(Х), . . ., Ck(X). При замене всех вхождений X на В мы по-прежнему получим правильное применение аксиомы с метапеременными Ml9 . . ., MkJ замененными на значения СХ(В), . . ., Cft(B). Проделав такие же замены во всех нетерминальных формулах вывода D, мы получим правильное дерево вывода/) с заключительной формулой А (В). Δ Δ Доказательство независимости аксиом и правил вывода в некотором исчислении, хотя и проходит обычно по общей схеме, но требует немалой изобретательности и хорошего понимания аксиоматики, как в ее содержательном смысле, так и в ее формальном (текстовом) представлении. С каждой аксиомой (или правилом вывода) связывается некоторое конкретное свойство формул или их интерпретаций. Это свойствод с одной стороньг, должно быть *) Если бы А'оказалась выводимой, то, осуществив обратную подстановку, мы получили бы выводимость А·
§ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИЯ 223· нетривиальным, т. е. среди выводимых должны быть формулы как обладающие, так и не обладающие этим свойством. С другой стороны, подмножество Μ формул, выводимых без применения данной аксиомы, должно быть замкнутым по отношению к свойству, т. е. формулы из Μ должны все либо обладать, либо не обладать этим свойством. Тем самым обнаруживается неполнота исчисления без данной аксиомы. Приведем два характерных примера доказательства независимости аксиом исчисления L. Независимость аксиомы А9: Если А—формула, то ЫА) —формула, полученная из А устранением всех вхождений зшша ~~~|. Например, h(-]x\/-}Y) zd -\-}X) = (х v Y) => х. Утверждается, что если А — любая формула, полученная заменой метапеременных на их значения в любой из схем аксиом А1 — А8, то ЦА) будет общезначимой формулой. Для этого достаточно убедиться, что для любой из этих схем h(A) так же получается из данной схемы, как и А. Например,, для А5 имеем Л((АУПВ)=)ПС=)((А\/"1В)&ПС))) = (А\/В)=> з(Сэ((А\/В)&С))г Назовем свойство выводимой формулы А иметь общезначимую* h(A) консервативностью А. Очевидно, что если АиАз В — консервативные формулы, то и В тоже будет консервативной. Итак, мы обнаружили, что множество формул, выводимых в исчислении L без аксиомы А9, обладает свойством консервативности. В то же» время (если взять в А9 А = В = А) формула й((ПА=>ПА)1э((ПА=эА)=эА)) = (А1эА)=э((А=эА)1эА) не является общезначимой (равна f при А = ι) и2 стало быть^ формула (ПА=э"1А)=э(ПА:эА)=эА) не выводима в L без А9. Независимость аксиомы A3: А& В =э А. В нашей интерпретации логических формул изменим определение конъюнкции. Будем считать, что х & У = у.
224 ГЛ. 6. КРАТКОЕ ПОВТОРЕНИЕ МАТЕМАТИЧЕСКОЙ ЛОГИКИ ' В результате конъюнкция получит следующую таблицу инстин- яости: X f f t t У t t f t х&У f t f t Рассмотрим исчисление L без A3. Непосредственной проверкой но таблицам истинности убеждаемся, что полученное исчисление корректно в этой новой интерпретации. В то же время формула (Х&У)=эХ не является общезначимой в этой же интерпретации (при X = f и Υ = t значение функции равно f). Таким образом, эта формула, получающаяся из схемы аксиомы A3, не выводима в исчислении L без A3. Заключение. Подведем итог изложенному в этой главе. Мы привели ряд конкретных фактов из алгебры логики и исчисления высказываний, которые нам потребуются в дальнейшем. Далее, на примере математической логики мы рассмотрели способ построения формальной теории как средства конструктивного изучения абстрактных объектов и их свойств. Конструктивность подхода состояла в том, что мы связывали с абстрактным объектом {булевой функцией) некоторую конструкцию (формулу), имеющую вид текста в некотором языке (язык логических формул), заданном своей формальной грамматикой (синтаксические правила). Связь формальных, но конструктивных объектов с содержательными, но абстрактными объектами устанавливается с помощью интерпретации. Одному формальному объекту может соответствовать ν множество интерпретаций (разное число независимых неременных в булевых функциях, разные определения операций, как это было в доказательстве независимости). Язык обычно создает избыточный запас конструкций и для выделения в этом запасе полезных для изучения конструкций строятся исчисления. Исчисления — это способ эффективного порождения формальных объектов, обладающих некоторым полезным свойством (например, свойством задавать одну и ту же функцию в алгребре логических формул или свойством быть общезначимой формулой в исчислении высказываний). Исчисление задается с помощью аксиом, которые играют двоякую роль. Они вместе задают исходное множество объектов1
ξ 6.3. ИСЧИСЛЕНИЕ ВЫСКАЗЫВАНИЙ 225 обладающих нужным свойством, а каждое само но себе является конструктивным носителем (постулатом) некоторого специального свойства абстрактного объекта. Правила вывода играют роль индуктивных определений, позволяющих строить (выводить) новые формальные конструкции по заданным, сохраняя при этом нужные свойства. При построении исчислений уделяется особое внимание возможности формулировать общие утверждения в формальной теории, т. е. относящиеся сразу к множеству конструкций. Для этого вводятся или особые правила подстановки и замены, или схемы аксиом и рассуждений с использованием метапеременных. Стандартными вопросами для исчислений являются вопросы корректности (замкнутости относительно исследуемого свойства), полноты формальной теории и независимости аксиоматики. Для некоторых читателей эта глава может оказаться первым знакомством с математической логикой. Перед ними автор должен особо извиниться за неполноту и некоторую поверхностность изложения. Формально этого материала достаточно, чтобы двигаться дальше, не теряя надежды понимать все до конца. Тем же, кого это изложение не удовлетворит, автор рекомендует несколько книг по математической логике, которые, кстати, служили и ему источником большинства определений и доказательств^ помещенных в этой главе: 1. И. А. Лаврову Л. Л. Максимова. Задачи по теории множеств, математической логике и теории алгоритмов. М., «Наука», 1975. Сжатая сводка основных понятий математической логики с хорошим ассортиментом познавательных и тренировочных задач. 2. П. С. Новиков. Элементы математической логики. М., «Наука», 1973. Вступительный курс, написанный с большой заботой о начинающем читателе. 3. Э. Мендельсон. Введение в математическую логику. М., «Наука», 1976. Современный и хорошо организованный вводный курс с весьма концентрированным изложением. 4. С. К. Клини. Введение в метаматематику. М., ИЛ, 1957. Непревзойденный по полноте и отличающийся строгостью кура повышенного типа, но вполне доступный для детального знакомства с основными понятиями.
ГЛАВА 7 ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА § 7.1. Начальные наблюдения Логические операторы в программах. Программа — это конструкция, побуждающая автоматическую машину к действию* Командная часть программы указывает содержание действия, а объектная часть — те данные (объекты), с которыми совершаются действия. В первой части книги мы изучали, в весьма упрощенной постановке, проблему экономного размещения данных в памяти машины. Размышляя о командной части программ, мы усматриваем в ней прежде всего два вида действий — преобразование данных (счет) и проверка свойств данных (управление). Свойства данных в программе задают условия выбора дальнейшего направления вычислений. Когда программист начинает решать задачу,^ он находит эти условия в содержательной формулировке: «является ли χ простым?», «матрица симметрична или нет?», «центром какой области является данный город?», «зацеплены ли компоненты связности информационного графа?», «сломается ли мост при ваданной нагрузке?», «выигрышна ли данная шахматная позиция?» Цель нашего исследования во второй части книги — построить некоторую общую теорию программирования условий. Глянув1 на приведенный выше список, мы видим, что первое, что нам надо сделать — это разумным образом .сузить задачу. Условия слишком разнообразны, а главное, скрывают в себе решение хотя и частных по отношению к общей программе задач, но самих по себе достаточно сложных. Один из подходов к уточнению постановки — это разделить способы формулирования и проверки условий от способов использования результатов проверки для выбора направления вычислений. В любом строгом определении программы это разделение достигается следующим образом. Вводится особый вид операторов, которые называются логическими операторами. Каждый оператор А состоит из двух частей: (1) некоторой произвольной функции /, определенной на объектах программы и принимающей одно из η допустимых заранее известных значений с19 . . ., сп, и (2) некоторого множества из η возможных преемников slf . . ., sn оператора Л. Функция / называется и- •начным предикатом. Правила языка программирования делаю*.
§ 7.1. НАЧАЛЬНЫЕ НАБЛЮДЕНИЯ 227 заранее (т. е. при написании программы) известным отображение области значений предиката {с1э . . ., сп) на множество преемников {su . . ., sn}*). Работа логического оператора состоит в вычислении значения предиката и в передаче управления на один из операторов su . . ,3 $п, соответствующий вычисленному вначению. Следующий шаг состоит в выделении важнейшего частного случая двоичного выбора, к которому по схеме, показанной на рис. 7-lj может быть сведен w-значный выбор (в скобках заметимл 1 7 Ζ S 4 5 β 7 в а) 1 ГУЛ 2 }\~ J J\ 4 у Φ S 8 7 д Рис. 7.1. Двоичные реализации и-значного выбора. *)л-значный выбор, б) Последовательная реализация, в)Каскадная реализация· что крайние случаи последовательной и каскадной реализаций л-значного выбора требуют одного и того же числа логических операторов в программе, однако среднее число двоичных выборов в первом случае будет порядка л/2, а во втором — порядка lg2n). Логические операторы с двоичными предикатами хороши не ι только тем, что они просты, но и тем, что позволяют для своей за-' писи использовать язык логических формул. При таком подходе' выражения предикатов имеют как бы двухъярусное строение.. Первый ярус образуют так называемые элементарные логические *) Сгрого говоря, число преемников не больше числа значений предиката, так как не будет противоречий, если «переключательная сила» предиката будет недоиспользована, т. е. разным его значениям будет соответствовать один преемник.
fe28 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА предикаты. Вторым ярусом предиката является произвольная логическая формула, в которой выражения элементарных предикатов играют роль независимых переменных, чьи значения истин· ности вычисляются некоторым внешним по отношению к логическому оператору способом. Такое использование предикатов первого яруса объясняет, почему они называются элементарными. Реально же, особенно в языках, допускающих произвольные функциональные обозначения, элементарный предикат может быть сколь угодно сложной вычислительной процедурой. Весьма развитой является структура логических предикатов в алголе 60. Ниже в бэкусово-науровой форме приведен синтаксис <простого логического выражения) алгола 60. Такие понятия как (переменная), (указатель функции) (т. е. обозначения вычисления функции для заданных значений аргументов) и (простое арифметическое выражение) (т. е. выражение, не содержащее условий) считаются известными *): (знак операции отношения) :: =<|<ζ |= |!> |> \ф (отношение) :: = (простое арифметическое выражение) (знак операции отношения) <(простое арифметическое выражение) (логическое значение):: = истина | ложь (первичное логическое выражение):: = (логическое значение) | (переменная) | (указатель функции) | (отношение) | ((логическое выражение» (вторичное логическое выражение)::' = (первичное логическое выражение) | ~~) (первшшое логическое выражение) (логический одночлен):: = (вторичное логическое выраже- - ние>| (логический одночлен) & (вторичное логическое выражение) (логический терм):: = (логический одночлен) | (логический терм>\/ (логический одночлен) (импликация):: = (логический терм) | (импликация) ζ> (логический терм) (простое логическое выражение):: = (импликация) ] (простое логическое выражение) = (импликация). Приведем несколько примеров предикатов, а) Условие, что χ принадлежит отрезку [0, 1 ]: (я<1)&(*>0). *) Выписано с заменой английских служебных слов на русские и знакаД на знак & из публикации «Алгоритмический язык алгол 60. Пересмотренное сообщение». М., «Мир», 1965.
§ 7.1. НАЧАЛЬНЫЕ НАБЛЮДЕНИЯ 229 б) Условие, что у находится за пределами полуинтервалов [а, Ъ) и [2в, 36): ~~\(а^у&у<Ъ\/ 2ха^у&у<ЗхЬ). в) Условие, что точка (X, У) находится в пределах тригонометрического круга, в его 1-й или 3-й четверти: (X f 2 + Y f 2<1)&(Хх У>0). г) «Машина голосования» — булева функция, истинная, когда по крайней мере два из трех логических аргументов истинны. Найти ее выражение проще всего, построив таблицу истинности: *1 i t i t χ» f * ) t t x* i t ! t F ' ! J f f t Χι t t t t χ* t f t t. x* f t ! t F 1 f t t t По таблице сразу находится совершенная нормальная форма: ~~}х!&х2&х3\/ х1&~~\х2&х.г\/ х1&х2&~~]х3\/ хг& х2 & х3. Правила построения логического оператора всегда предусматривают два возможных направления вычислений, назовем их плюс- направлением и минус-направлением. Плюс-направление связывается с истинным значением, предиката-условия, а минус- направление — с ложным. В одних алгоритмических языках плюс-направление указывается меткой, а минус-направление означает следующий текстуально оператор; в других языках оба направления указываются метками, причем первая метка считается плюс-меткой, а вторая — минус-меткой. В алголе 60 плюс-направление указывает на оператор (он может быть, как известно, составной), стоящий между словом то и словом иначе или ; . В случае; минус-направление не требует никаких действий, и происходит переход к следующему текстуально оператору. В случае иначе минус-направление указывает на оператор, стоящий сразу за иначе. Логический оператор в алголе 60 называется условным оператором и задается о помощью следующего синтаксиса: <условие>:: = если (логическое выражение) то (безусловный оператор) :: = (основной оператор) | (составной оператор) | (блок)
230 ГЛ, 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА < оператор «если»):: = <условие> <безусловный оператор) <условный оператор):: = (оператор «если») | (оператор «если») иначе (оператор) | (условие) (оператор цикла >*) | (метка)>: (условный оператор) Если вспомнить, что среди основных операторов есть оператор перехода на М, то станет ясно, что синтаксис алгола 60 охватывает и другие способы указания плюс- и минус-направлений. Ниже следуют несколько фрагментов алгольских программ с логическими операторами, использующими вышеприведенные логические выражения в качестве условий: 1) если (х ^ 1) & (х ^ 0) то у:=* χ иначе i/:= In (x); 2) если (Х|2 + У|2< 1)&(Х χ Υ > 0) то начало если ХфО то начало Л:= arctg (У/Х); на СЧЕТ конец конец; ОШИБКА: вывод (Χ, Υ) 8) если Π #1&Я2&Яз V χι& Π^2&^3 V #ι&#2& Π #з\/ V хг&х2&.хь то на ДА иначе на НЕТ / В нашем изложении, так же как и в первой части, нам будет .удобно изображать программы графически. Поскольку передачи управления в графе переходов указываются дугами, ориентация которых указывается стрелками, естественно называть плюс- и минус-направления соответственно плюс- и минус-стрелками. При этом плюс-стрелка будет отличаться от минус-стрелки точкой у своего основания. На рис. 7.2 в графической форме повторены примеры логических операторов. Задача о голосовании. После повторительной главы по математической логике нам естественно сосредоточиться на примере «машины голосования». С одной стороны, в его условии стоит довольно громоздкое выражение, с другой стороны, реализовать его вычисление ничего не стоит: нужно только набраться терпения и запрограммировать совершенную нормальную форму: jr2:=» гг&х2; 7Ί: = Π х2; ί r1:r=r1&x1; Γι: « rx & xz\ r2: =raVi; m ■ < *) Для читателя будет неплохой задачей додуматься, почему авторы ал· гола 60 не причислили <оператор цикла) к безусловным операторам): ведь ках будто <оператор цикла) сочетается с <условием> так же, как и безусловный оператор)·
§ 7.1. НАЧАЛЬНЫЕ НАБЛЮДЕНИЯ 231 ri: = rl& x2; г2: =г2 V гг; гх: = ζχ & я2; Γι: = хг & х2; гг: = ι\ V 'У, если гх то на ДЛ иначе на НЕТ. Автор убежден, что в этом месте даже самый робкий читатель возмутится тратой бумаги на демонстрацию столь бездарного а) ОШИБКА Выводу Υ) Аг=отйдОУХ) Φ СЧЕТ. ~\Х-1 &,Х2ЬЯ3Ч Χΐ&ΛΧ2&Χ3\Ι Xf ά Xf&.'lXjV X-jh Xg&Xj НЕТ β) Рис. 7.2. Прпмеры логических операторов. «} Альтернативные ветви с общим преемником, б) Цепочка условий с уходом из вегви. в) Сложное условие. подхода к программированию этой задачи. Автор просит прощения и сообщает, что пример приведен для контраста, а также для предупреждения, что на практике такие программы появляются, к сожалению, не так уж и редко.
232 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА Без всякой математической логики и общей теории программирования тремя заданными величинами хи х2 и х3 можно распорядиться очень просто! Пусть хх и» t. Проверим х2\ если х2 = t, то мы имеем два голоса и можем сказать ДА; если х2 = f, то при х3 = t мы получаем^ снова ДА, а при х<6 = f — НЕТ. Пусть χγ = f. Проверим ay- если #2 = *» то опять все зависит от #3: при #3 ^ * имеем ДА, а прия^ f — НЕТ; если #2 = f t то мы уже имеем два против: НЕТ, Эта процедура выбора легко изображается графически (рис. 7.3, а). Глядя на нее, мы сразу соображаем, что проверку х3 ДА. НЕТ'ДА . НЕТ ДА НЕТ а) ф Рис. 7.3. Машина голосования. а) Непредвзятый прямой^ подход, б) Усовершенствованный прямой подход. нет смысла выписывать два раза; достаточно завести стрелки от двух проверок х2 на одну вершину графа (рис. 7.3, б). Мы видим, что расчленение сложных логических условий на серию проверок элементарных предикатов может привести к заметному упрощению программы. На этот раз автор вправе рассчитывать на определенный скептицизм читателя, потому что такое прямое рассуждение, скажем, для десяти голосующих будет, возможно, заметно сложнее или чревато ошибками. Поэтому естественно рассмотреть способы расчленения сложных предикатов на элементарные более систематически. При этом мы сразу выходим на разумное сужение задачи (методологически — точно так же, как и при введении понятия логической формулы): мы отвлечемся от способов вычисления элементарных предикатов, считая их независимыми логическими переменными, чьи значения задаются другими (счетными) операт
§ 7.1. НАЧАЛЬНЫЕ НАБЛЮДЕНИЯ 283 торами программы. Сам предикат при этом становится просто логической формулой. Поскольку формула составляется из переменных с помощью логических операций, естественно и вопрос расчленения предиката услрвия выяснять, подвергая анализу главные логические операции. Соответствующие правила обнаруживаются немедленно: 1) Отрицание. Если условием является отрицание ~~| xt то, чтобы проверять х, нужно в операторе поменять местами плюс- и минус-направления (рис. 7.4, а). 1 Ζ VA> ГГПа в) 1 2 .г) J 2 Рис. 7.4. Правила расчленения условий. а) Отрицание, б) Дизъюнкция, в) Конъюнкция, г) Импликация* 2) Дизъюнкция. Если условием является дизъюнкция χ V У, то надо проверить χ с выходом на плюс-направление при χ = t и с переходом к проверке у при χ = f. Выходы от проверки у — те же, что и у χ \J у (рис. 7.4, б)). Заметим, что это правило непосредственно опирается на известные свойства дизъюнкции t V у = *, ί V у = у. 3) Конъюнкция. Если условием является конъюнкция х&уу то надо проверить χ с выходом на минус-направление при х = f и с переходом к проверке у при χ = t. Выходы от проверки у — те же, что и у х&у (рис. 7.4, в). Заметим, что это правило опирается на аналогичные свойства конъюнкции
234 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА 4) Импликация. Если условием является импликация χ zd у, то надо проверить χ с выходом на плюс-направление при χ =» f и с переходом к проверке у при χ =* t. Выходы от проверки у — те же, что и у χ zd у (рис. 7.4, г)). Здесь работают следующие свойства импликации: . f zd у = t, t zd г/ = г/. Сформулировав эти правила, мы легко обнаруживаем, что они зависимы друг от друга: можно взять за основу правила отрицания "rzr —I Gl^~Z) ^^ 0(Ί<2;νΊ^0 rv; (ί^νΊ^ Υ I У Υ I ν Рис. 7.5. Получение выводимых правил." а) Правило для конъюнкции, б) Правило для импликации. (ТЗ—тождественная эамена условия, ρ — применение правила для операции μ). ' и дизъюнкции и вывести из них правила конъюнкции используя соотношение *&»=nn*v~W и импликации, используя тождество xzDy = ~~\x\ly. Этот вывод показан на рис. 7.5.
§ 7.1. НАЧАЛЬНЫЕ НАБЛЮДЕНИЯ 235 Очевидно, что применяя эти правила, можно совершенно формально расчленить произвольный логический оператор, используя дерево разбора логической формулы, образующей условие. Мы порекомендуем читателю проделать такое расчленение для условия в «машине голосования» и сравнить результат о программой, показанной на рис. 7.6, а). Посмотрим внимательно на то, что у нас получилось. Естественно, программа очень далека от элегантной схемы голосования с рис. 7.3, б). Однако именно бросающаяся в глаза несуразность программы (каждое условие проверяется четырежды) подсказывает намА что здесь что-то можно сделать. Проведем содержательный анализ программы на рис. 7.6, а)/ Она состоит из четырех «этажей», на каждом из которых есть «коридор» с выходом в конце и с четырьмя «лестницами» на начало нижнего этажа. Двигаясь по коридору от начала, мы последовательно проверяем значения элементарных предикатов и в зависимости от комбинации их значений либо попадаем на концевой выход, чтобы сказать ДА, либо спускаемся по лестнице на начало коридора в нижнем этаже. Шансы на улучшение программы состоят в том, что, попав на какой-то этаж Ρ по лестнице, идущей сверху, мы уже знаем значения некоторых предикатов и могли бы на этаже Ρ и далее сразу выбрать нужное направление, не спрашивая дорогу. Проверим эту идею более внимательно, начав с нижних этажей программы. Перед этим, чтобы не загромождать чертежи,, еще более схематизируем изображение программы, заменив переменные на их номера, сократив ДА и НЕТ до Д и Я" и не вырисовывая детально части программы,, выходящие в данный момент за поле зрения (см. рис. 7.6, б)). Если при начале движения по второму этажу хг окажется ложным, то, попав по минус-стрелке от хх на первый этаж, мы обнаруживаем, что условие хх с первого этажа обязательно нас переадресует на Я. Но если так, то мы можем в нашей программе перенести минус-стрелку, идущую от второэтажного хи прямо на Я, устраняя повторную проверку того же условия (рис. 7.6, в)). Если мы попадем на первый этаж от второэтажного условия #2, то это будет возможно только при ^"tiije f. Однако при движении по первому этажу эта комбинация значений непременно переадресует нас на Я. Выяснив это, мы опять-таки можем перенести минус-стрелку от второэтажного х2 прямо на Я (рис. 7.6, г)). Рассуждая аналогично для случая попадания на первый этаж от второэтажного х3, мы переносим плюс-стрелку от него прямо на Я и получаем программу, показанную на рис. 7.6, д). Мы обнаруживаем два интересных момента. На первый этаж теперь не ведет ни одна лестница. Таким образомА на эту часть
23β ГЛ.7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА в). м) з) Рис. 7.6. Систематическое упрощение «машины голосования».
§ 7.1. НАЧАЛЬНЫЕ НАБЛЮДЕНИЯ 237 программы нельзя ниоткуда попасть и, стало быть, ее можно просто устранить из программы. В логическом операторе с условием хд на втором этаже плюс- и минус-направления совпадают и поэтому выполнение проверки не нужно. Это позволяет перенести плюс-стрелку, идущую на вход х3, прямо на Д, а оператор с х3 убрать (рис. 7.6, е)). Повторение аналогичных рассуждений для следующей пары этажей приводит нас к программе, показанной на рис. 7.6, ж). После последней серии переноса стрелок мы получаем программу, изображенную на рис. 7.6, а). Выбросив логический оператор с хъ на который теперь не ведет ни одна передача управления, склеив два одинаково работающих экземпляра оператора с условием х3 и вернувшись к прежним обозначениям, мы обнаруживаем желаемый результат (сравните рис. 7.6, и) с 7.3, б)). Начальная постановка задачи. Этот пример позволяет нам сделать ряд важных наблюдений, закладывающих основу нашего исследования. Мы рассматриваем программы, содержащие условия, которые вычисляются как булевы функции от элементарных предикатов и изображаются в виде логических формул, содержащих основные логические операции. В этих программах можно выполнять эквивалентные преобразования, изменяющие структуру логических операторов, но не меняющие содержание программы. Правила этих преобразований имеют вид тождественных соотношений между фрагментами программ в их графическом представлении. К ним относятся, в частностиг правила расчленения (и сочленения, если читать их справа налево) условий (рис. 7.4), а также правила переноса стрелок (исключение повторных проверок), устранения неработающих операторов и «расклеивания» (или склеивания) одинаково работающих операторов (рис. 7.7). Частично эти соотношения опираются на свойства булевых функций, и частично — на правила выполнения логических операторов. Преобразования программ, опирающиеся на эти соотношения, могут приводить к улучшению тех или других характеристик программы (простота, более четкая структура, меньшее время работы). Поэтому естественно возникает задача: построить исчисление преобразований программ, сохраняющих эквивалентность и связанных с работой логических операторов. Знакомство с исчислением высказываний сразу подсказывает нам, из каких частей должно состоять решение этвй задачи. 1. Надо построить язык, в котором будут конструктивно описываться формальные объекты, соответствующие реальным программам. Эти формальные объекты получат у нас название схем Янова. 2. Надо описать механизм интерпретации, позволяющий сопоставлять схемы Янова реальным программам и ввести отношение эквивалентности между программами.
*38 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА 3. На основании эквивалентности программ надо дать определение эквивалентности схем Янова и исследовать его. / / Χι C\J д / 2 I Л 12 7 Φ rxj г) Г Л Рис. 7.7. Дополнительные правила преобразований. «) Непосредственный перенос плюс-стрелки, б) «Дистанционный» перенос плюс-стрелки, в) Устранение неработающего логического оператора* г) Склеивание одинаково работающих логических операторов. 4. Надо ввести метаязык, в котором будет описано исчисление» равносильных (т. е. сохраняющих эквивалентность) преобразований схем Янова, и придумать само исчисление. 5. Надо будет исследовать найденное исчисление на предмет его корректности и полноты, составляющих его аксиом и правил вывода·
§ 7.2t ПОИСК ОСНОВНЫХ ОПРЕДЕЛЕНИИ 239 § 7.2. Поиск основных определений Анализ ограничений. Первое, что надо сделать — это очертить рамки нашего формализма. Ряд важных ограничений мы уже отметили. Главное — это то, что мы изучаем такие свойства программ, которые связаны с условными операторами, при этом только с их «вторым ярусом» — булевой функцией от элементарных предикатов. Это значит, что остальные операторы программы нас сами по себе не интересуют, и для нас важно только, чтобы последовательность их выполнения, задаваемая логическими операторами, не нарушалась бы при тех или иных манипуляциях с условиями. Такой подход хорошо виден в примере «машины голосования»: мы исследовали механизм проверки условий в куске программы, содержащем только условия и имеющем один вход и два выхода — ДА и НЕТ, при этом заботились лишь о правильности выбора выхода в зависимости от значений логических переменных, поступающих на вход. Можно было бы на этом остановиться, построив «алгебру логических операторов», вводя в качестве интерпретации функцию выбора нужного выхода и гарантируя сохранение этой функции при преобразовании логических операторов. Однако у&е простые примеры показывают, что нам естественно хотеть большего. Мы видели, что одним из способов упрощения сложных логических операторов является «запоминание» результата проверки значений условий: это позволяло нам избегать повторных проверок и устранять становящиеся ненужными логические операторы. Влияние выбора направления, т. е. вычисленного значения условия, распространяется не только на ближайшего преемника (рис. 7.7, а)), но при определенных условиях носит дистанционный характер (рис. 7.7, б)); при этом цепочка условий, вдрль которых как бы переносится информация о сделанных ранее выборах, может быть достаточно длинной. Спрашивается, однако, как поступать, если на пути такой цепочки встает счетный оператор (рис. 7.8)? Очевидно, что ответ зависит только от того, перевычисляет А величину χ или нет. Действительно, если мы достоверно знаем, что оператор А не может изменить яначение переменной #, то дугу, выходящую из Л, можно направить сразу на выход 1. В противном случае такое преобразование может оказаться незаконным. Таким образом, мы заключаем, что операторы целесообразно включить в формализм, а протяженность логических зависимостей нЬбуждает распространить наш формализм на понятие программы в целом. В качестве упрощающего обстоятельства мы можем, однако, подчеркнуть, что формальное понятие счетного оператора требует немногого: умения отличать в программе один оператор от другого и внания для каящого
240 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА оператора тех логических переменных, которые могут быть изменены этим оператором. Разумное определение программы требует введения памяти, хранящей перерабатываемые данные. Один вид памяти у нас уже есть — логические переменные, хранящие значения элементарных предикатов, вычисляемые тем или иным оператором или задаваемые перед началом работы программы. Что же касается памяти для остальных данных, перерабатываемых программой, то туг дело обстоит одновременно и проще и сложнее. Мы уже отметили, Если Ане влштна χ А А 2) 5 &' 1 3 Г f 7 2 Рис. 7.8. Перенос стрелки при наличии счетного оператора. что все, что нам нужно от счетных операторов — это знать, какие условия какой оператор может перевычислять. Какие другие данные воспринимает или вырабатывает оператор — нам не интересно. Это пренебрежение к деталям работы оператора можно выразить допущением, что как аргументом, так и результатом оператора является как бы вся память в целом. При таком подходе память для данных выглядит как некоторое монолитное устройство, не требующее разбиения на ячейки. Такая память может в операторах лишь подразумеваться, не требуя явного обозначения и, стало быть, просто не появляться в формальном определении схем Янова. Негативной стороной такого допущения является обеднение теории. «Тотальный» эффект действия любого счетного оператора — со всей памяти на всю память — является, конечно, слишком сильным предположением, не оправдывающимся для большинства реальных программ. Зато (несколько забегая вперед) мы заметим, что именно это огрубление исходных предпосылок позволило придать теории Янова классическую законченность. Как и в случае задачи об экономии памяти, нам естественно объединять операторы в программу с помощью графа переходов. И здесь первая задача — это выбрать способ представления графа
§7 2. ПОИСК ОСНОВНЫХ ОПРЕДЕЛЕНИЙ 241 и степень его общности. Поскольку мы уже ограничили себя логическими операторами с двоичными предикатами, сосредоточив на них все функции выбора направления счета, у нас появляется естественное требование, что бы любая вершина графа переходов имела не более двух преемников. Поскольку при интерпретации схем Янова нужно будет, описывать вычислительный процесс, задаваемый программой, нам надо указать в графе переходов начальный и заключительный операторы. Если мы допустим несколько начальных операторов, то мы должны подразумевать существование некоторого акта «самого начального» выбора начального оператора. Мы не видим особой надобности в создании такой дополнительной сущности и предполагаем обязательное наличие одного начального оператора, который будет помечаться особой входной стрелкой. Заключительный оператор естественно трактовать как команду останова, т. е. такой оператор не осуществляет никакого преобразования данных и не назначает преемника. Логично потребовать, чтобы в графе переходов соответствующая вершина не имеЗга выходящей из нее дуги. Легко согласиться с тем, что нет принципиальной разницы между одним или несколькими заключительными операторами. Мы ограничимся для большей простоты одним. Следующей альтернативой является одно- или многосвязность графа переходов. Читатель помнит, что в задаче об экономии памяти мы потребовали связности. Там этого было достаточно, так как процедура экономии к каждой компоненте связности применялась независимо, а сам граф был неизменным. В нашем случае мы уже знаем, что граф переходов при преобразовании схем Янова будет меняться, в частности, возможно размножение вершин и перенос дуг с одних вершин на другие. У>ке примера с «машиной голосования» достаточно, чтобы догадаться, что даже если требовать связности исходного графа, в ходе преобразований связность может нарушиться. Это обстоятельство подсказывает нам не налагать дополнительных ограничений на граф переходов. Говоря о языке описания схем Янова, нам может показаться необходимым предложить некоторое текстовое представление графа переходов. Автор, однако, в этом месте хочет показать читателю, что можно применять понятие языка не так уж буквально иг где возможно, трактовать конструктивные объекты как абстрактные, а где нужно, использовать * другие наглядные формы представления объектов, нежели текстуальное. В частности, мы дадим определение схем Янова, используя абстрактное понятие ориентированного графа и не вводя особых символов (до поры до времени) для таких его характеристик как входная стрелка, плюс- и минус-стрелка и заключительный оператор. Для того чтобы лучше сочетать абстрактную трактовку графа и символический язык, задающий операторы и логические
242» ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВ А условия, мы будем считать, что граф переходов состоит из абстрактных вершин, которым сопоставлены конкретные операторы и логические условия., Определение схемы Янова. Пусть даны счетное множество предикатных символов & = (Pi. Ръ · · ·} и операторных символов Ж = {Аг, А2, . . .}. Условием называется любая логическая формула с предикатными символами из &* в качестве логических переменных. Оператором А = А (Р) называется пара, состоящая из операторного символа А и некоторого множества (возможно, пустого) Ρ предикатных символов. Множество Ρ = Ρ (А) называется сдвигом оператора А. Графом переходов называется ориентированный граф, множество вершин которого состоит из неотрицательного числа преобра- вователей, неотрицательного числа распознавателей и одного останова. Каждый преобразователь имеет одного преемника, каждый распознаватель — Двух преемников. Дуги,исходящие из распознавателя, различаются и называются соответственно плюс-стрелкой и минус-стрелкой. Останов преемника не имеет. Одна вершина в графе переходов называется входной и помечается входной стрелкой. Пусть {/>!, . . ., pk} — произвольное непустое множество предикатных символов. Схемой Янова G(px, . . ., pk) называется любой граф переходов, распознавателям которого сопоставлены условия, а преобразователям — операторы; при этом логические переменные каждого из условий и каждого из сдвигов операторов принад- у pfe}, а Β°θ операторные символы Рис. 7.9. Схема Янова. лежат множеству {рг, операторов схемы попарно различны. На рис. 7.9 приведен пример схемы Янова, который одновременно поясняет принятые нами графические обозначения всех элементов формального определения.
§ 7.2. ПОИСК ОСНОВНЫХ ОПРЕДЕЛЕНИЙ 243 Рис. 7.10 содержит примеры разного рода дегенеративных 'схем, которые позволят нам, в частности, проверить правильность теории для различных «крайних случаев». {*} (Й) s а) Φ 1 {Л7} В(р) С(Ф Φ {а,Ь} <*> М) ШХ) ¥) Φ Рис. 7.10. Примеры дегенеративных схем Янова. «) Самая пусгая схема, б) Многосвязная Схема, в) Неполносвязные схемы* г) Схема без операторов, д) Схема без условий. На рис. 7.11 изображена схема Янова для «задачи о трех экспертах». Сделаем необходимые пояснения к схеме. Три эксперта, Э1э Э2 и Э3, отвечают за принятие или отклонение
244 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА некоторого документа. Процедура прохождения документа через экспертный совет состоит в следующем. Вначале эксперты понаслышке имеют какое-то предварительное мнение о документе! хг = ί означает, что Эг одобряет документ. Эх и Э3 — скептики. Рис. 7.11. Задача о трех экспертах. Это значит, что если они знают о документе с плохой стороны, то они готовы, не читая документа, отправиться на голосование. Если же документ понаслышке хорош, то они предпочитают прочитать документ (Л],(£]) для Эх и А3{х4) для Э3)7 что, естественно,
§ 7.3. ЭКВИВАЛЕНТНОСТЬ СХЕМ ЯНОВ А 245 может повлиять на их оценку. Э2 — доброжелатель и поступает противоположным образом: если документ понаслышке хорош, он готов голосовать, не читая документа, а в противном случае занимается его изучением (оператор А2(х2)). После этого имеет место пробное голосование (производящееся по формуле рассмотренной ранее «машины голосования»). Если пробное голосование оказалось единогласным и положительным, то документ считается принятым. В остальных случаях он становится предметом серии кулуарных бесед. Эти беседы происходят при попарных встречах экспертов (оператор Ац (xt, xj) означает согласительную беседу экспертов Э^ и Э,·). Если им удается сблокироваться, то, полагая результат предрешенным, они отправляются на повторное голосование. Серия кулуарных разговоров повторяется, если до этого ни одна из трех парных бесед к образованию блока не привела. Положительное повторное голосование означает принятие документа. В случае отрицательного заключения имеет место переработка документа (оператор А(хг, х21 х3)), после чего цикл прохождения документа повторяется. § 7.3. Эквивалентность схем Янова Функциональная эквивалентность. Пусть дана схема Янова G(pi, . . ., pk) с операторными символами А19 . . ., Ап. Для того чтобы превратить схему в способную к действию программу, нам нужно дать некоторую интерпретацию ее операторным и предикатным символам, а потом описать алгоритм выполнения интерпретированной схемы. Прежде всего задаемся некоторым множеством D состояний памяти d: D — {а1}. Поскольку мы изучаем такие свойства схем, которые справедливы для любых интерпретаций, природа этого множества нас не интересует. Далее, мы сопоставляем каждому предикатному символу Pi (i = 1, . . ., к) некоторую функцию-предикат яДй), отображающую D на множество логических значений {f, t}: я,:Я —{f,t>. Сам символ pi будем при этом трактовать как предикатную переменную. Наконец, каждому операторному символу Aj (j = 1, . . ., η) сопоставляется некоторая (возможно, частичная) функция φ7·(ώ), отображающая D в D: <pjг : D -+ D. После такого сопоставления алгоритм работы интерпретированной схемы выглядит следующим образом.
246 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА Начальный шаг. Берем произвольное dEiD в качества исходного состояния памяти, затем производим присваивание значений всем предикатным переменным: РГ-= лг(а) (i = 1, . . ., к), после чего передаем управление на входную вершину графа переходов. Шаг выполнения. Пусть а—текущее состояние памяти, Δ = (alf ...» Ok) — упорядоченный набор текущих значений: предикатных переменных и управление передано на вершину £# а) Пусть ι? —останов. Тогда d объявляется результатом выполнения схемы в данной интерпретации, а само выполнение завершается. б) Пусть S — распознаватель с условием F(plf . . ., pk).. Вычисляем σ = F(A), и передаем управление на преемника распознавателя по плюс-стрелке, если σ = t, и на преемника по минус-стрелке, если σ = f. в) Пусть S— оператор A j(Pj). Вычисляем новое текущее состояние памяти d! = <Pj(d)· Каждой предикатной переменной p^Pf присваиваем новое значение в результате чего образуется новый набор Δ' текущих значений предикатных переменных. После этого передается управление на единственного преемника оператора Aj. Поскольку каждый шаг выполнения схемы G с интерпретацией I однозначно определяется текущим состоянием памяти, заключительное состояние памяти d становится тем самым функцией FGtI исходного состояния d0: Очевидно, что в общем случае эта функция частична. Кроме частичной определенности функций, интерпретирующих формальные символы схемы, логически возможны еще две причины неопределенности результата: а) бесконечное выполнение — выполняя оператор за оператором, мы никогда не попадаем на останов; б) пустой цикл — переходя от распознавателя к распознавателю, минуя операторы, мы попадаем вновь на ранее пройденный распознаватель. Так как каждый распознаватель срабатывает однозначно, а значения предикатных переменных не изменились, цикл передач управления будет выполняться неограниченное* число раз. Мы назовем две схемы Янова Gx и G2 сравнимыми, если они: ваданы каждая над одним и тем же множеством предикатных сим-
§ 7.3. ЭКВИВАЛЕНТНОСТЬ СХЕМ ЯНОВА 247 волов, а также, если операторные символы в операторах AxeG| и А2еС?2 одни и те же,, то и Р(Аг) = Р(А2). Сравнимость схем позволяет дать каждой из них совместную интерпретацию, когда всем предикатным и общим операторным символам будут сопоставлены одни и те же функции, а одинаковость сдвигов приведет к тому, что на одинаковых состояниях памяти одинаковые операторы будут также одинаково срабатывать. Определение. Две сравнимые схемы Gx и G2 эквивалентны в совместной интерпретации /, если Под равенством частичных функций мы понимаем такое положение, что если для некоторого d определена одна функция, то определена и другая, и их значения совпадают. Определени е. Две сравнимые схемы G± и G2 функционально эквивалентны, если они эквивалентны в любой совместной интерпретации. В определенном смысле — это наиболее естественное определение эквивалентности схем. Однако само по себе оно не дает подходящей зацепки для того, чтобы устанавливать эквивалентность схем или строить систему равносильных преобразований. Операционная эквивалентность. Опыт отладки реальных программ подсказывает нам, что гораздо легче устанавливать правильность работы программы, если располагать не только результатами вычисления, но еще и некоторой историей их получения. По-видимому, легко согласиться, что весьма детальной историей работы программы будет полная последовательность выполняемых оперйоров и наборов значений предикатных переменных. Последовательность операторов позволит восстановить последовательность состояний памяти, а наборы значений предикатных переменных восстанавливают путь от одного оператора к другому. Эту двойную последовательность мы назовем операционной историей выполнения интерпретированной схемы Янова. Дадим более точное определение операционной истории. Пусть дана интерпретация / схемы G. Будем называть последовательность значений предикатных переменных верхней последовательностью, а последовательность операторов — нижней. Начальный шаг. Верхняя и нижняя последовательности пусты. Пусть дано исходное состояние памяти d. Вычисляем текущий набор Δ значений предикатных переменных и помещаем его в верхнюю последовательность. Переходим ко входной вершине. Шаг выполнения. Управление передано на вершину S <5 текущим набором Δ значений предикатных переменных. а) Если S — это распознаватель с условием F, то смотрим, помечен он или нет. Если он не помечен, то домечаем его и
248 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА переходим к нужному преемнику в зависимости от вычисленного условия F(A). Если S оказался помеченным, то это значит, что мы попали в пустой цикл. Выполнение схемы обрывается, операционная история и результат выполнения схемы не определяются. б) Если S— это останов, в нижнюю последовательность записывается символ останова [><], выполнение схемы завершается, операционная история построена, текущее состояние памяти объявляется результатом работы программы. в) Если S— это оператор, то он выполняется, образуя новое состояние памяти, его операторный символ записывается в нижнюю последовательность, должным образом перевычисляется набор значений предикатных переменных, вся разметка распознавателей снимается, управление передается единственному преемнику оператора. Операционная история, так определенная, становится тем сдмым для схемы G в интерпретации / однозначной функцией HGt j (d) исходного состояния памяти d. Аналогично предыдущему, мы скажем, что две сравнимые схемы С?! и G2 одинаково работают в совместной интерпретации /, если HGlJ(d) = HG2tI(d). Определение. Две сравнимые схемы Gx и G2 операцион- но эквивалентны, если они одинаково работают в любой совместной интерпретации. Связь введенных эквивалентностей. Появление двух независимых определений эквивалентности схем Янова требует их совместного изучения. Взаимную связь функциональной и операционной эквивалентности исчерпывает Теорема 1. Две сравнимые схемы Янова функционально эквивалентны тогда и только тогда, когда они эквивалентны операционно. В сторону от операционной эквивалентности к функциональной доказательство непосредственно вытекает из определений: поскольку* последовательность операторов в операционной истории в точности такова, каков их порядок применения к памяти при выполнении интерпретированных схем, а исходное состояние одно и то же, то на любом шаге применения операторов операционно эквивалентных схем мы будем иметь одинаковые состояния памяти, в том числе и после перехода к останову. В обратную сторону доказательство более сложно и существенно опирается на то, что схемы эквивалентны для любой интерпретации. Принципиальная идея доказательства заключается в том, что подыскивается особая интерпретация F, которая в памя-
§ 7.3. ЭКВИВАЛЕНТНОСТЬ СХЕМ ЯНОВА 249 ти накапливает операционную историю выполнения схемы. В зависимости от выбранного исходного состояния формируется та или иная история вычислений. Разнообразия исходных состояний достаточно, чтобы создать в процессах выполнения схемы все возможные ее операционные истории. Оказывается, что если одна схема вырабатывает некоторую операционную историю, то другая схема не может выработать другую, так как в этом случае нарушилась бы эквивалентность в интерпретации V. Состояния памяти изображаются двумя словами, h и w, где h — слово в алфавите логических значений и операторных символов: оно будет накапливать операционную историю выполнения интерпретированной схемы. В свою очередь w — это бесконечная последовательность логических значений: оно будет источником наборов текущих значений предикатных переменных при очередном шаге выполнения программы. Назовем пару наборов логических значений (Δ, Δ') допустимой для оператора А(Р), если множество номеров компонент, в которых наборы ДиА' отличаются друг от друга, является подмножеством номеров предикатных символов, принадлежащих сдвигу Р. По определению, оператор. А(Р) может при своем срабатывании перевычислить только те предикатные переменные, которые входят в сдвиг Р. Таким образом, допустимая пара — это такие Δ и Δ', что Δ может быть «сдвинут» до Δ' с помощью А(Р). Определим теперь точно интерпретацию V. Пусть функционалов эквивалентные схемы Gx и G2 даны над предикатными символами /?!, . . ., pk и содержат вместе операторы Л^Р^, . . . ..., Λη(Ρη); φ;·(^, w) определена и равна (/&', и/) тогда, когда w = — ΔΔΏ, где (Δ, Δ') — любая допустимая пара для оператора Aj(Pj), а Ω — «остаток» слова w. В этом случае h' = hAA;, w' = ΔΏ. Для остальных состояний памяти φ7· не определена (/ = 1, . . м п). n^h, w) определена всегда и равна i-й букве слова w (i = 1, . . ., к). Напомним, что 0 обозначает пустое слово. Лемма 1. Если в интерпретации V схемы G(plt · · ., ph) FG,v(0,w) = (h',w')t то h'A^ = HGyV(0,w)*)r еде Δ — первые к букв слова w\ *) Для того чтобы конструкции были формально сравнимы, мы полагаем, что в Я верхняя и нижняя последовательности слиты в одну: &oAit&tAiu 31 Т. Д.
250 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА Точное доказательство этой леммы, которое предоставляется читателю, требует индукции по числу шагов выполнения схемы G в интерпретации V на исходном состоянии памяти (0, w). V Итак, рассмотрим любую интерпретацию / и любое исходное состояние памяти d, для которых определено выполнение хотя бы одной из схем Gx и G2 и, стало быть, FGi,i(d) = FC2iI(d). ^ Рассмотрим операционную историю данного вычисления любой и» этих схем, скажем, Gx: „ ... Δο Δχ ... Δ/{ ЯС>^) = Α. ... Aik И- Возьмем в интерпретации V исходное состояние памяти (й0, w0), где К = 0/ где Ω — любая бесконечная последовательность логических значений, а 0 — пустое слово. Утверждается, что в этом случае FguV (V и>о) = (A0^A ... 4ffc, ΔΛΩ). Доказательство этого утверждения практически совпадает с доказательством леммы, с одной лишь разницей: в лемме мы доказываем, что в интерпретации V схема в слове h фиксирует историю своей работы, какова бы она ни была, а в этом утверждении мы обнаруживаем, что выполнение воспроизведет именно ту историю,, которая нас интересует, а именно HGuI (d). Так как схемы Gx и С?2 эквивалентны в любой интерпретации, в том числе и в V, то мы получаем, что Fg2,v (й0, wo) = (Δο^ίΑ ... Aih, AkQ). В силу леммы мы заключаем, что Hg2,v (К, w0) = A^Aj... AikAk.~ Теперь нам осталось показать, что и история вычисления FG2,x будет той же самой. Поскольку мы рассматриваем совместную интерпретацию схем Gx и С?2, то начальное - значение предикатных переменных Pit · · ·> Ph Для ^2 на начальном состоянии памяти d будет то жа самое, что и для Gx, т. е. Δ0. История работы G2 в интерпретации V показывает нам, что на входном наборе Δ0 первым выполняемым оператором в G2 будет оператор Αίχ, τ, е. тот же, что и в исто-
§ 7.3. ЭКВИВАЛЕНТНОСТЬ СХЕМ ЯНОВА 251 рии HGtj{d). Опять-таки в силу совместности интерпретации «осле срабатывания оператора Aix в схеме G2 мы получим то же состояние памяти d' = φι, (d) и тот же набор значений предикатных переменных Ац что и в HGl,i(d). Повторив только что проведенное рассуждение шаг за шагом, мы получим, что HG2j(d) = #с.у (Л0, w0) = ffGiiI (d), что и требовалось доказать. VV Следствие. Если две схемы Gx и G2 эквивалентны в интерпретации V, то они эквивалентны в любой интерпретации. Действительно, пусть для некоторой интерпретации / и исходного состояния памяти d определены FGx,i(d) и соответствующая ■операционная история HGt,i(d). В интерпретации V существует начальное состояние памяти (/г0, w0), вычисляющее эту историю. Так как Gx и G2 эквивалентны в V, это же состояние памяти создает такую же историю для С?2. Повторив заключительное рассуждение теоремы, мы убедимся, что эта же история будет получена при вычислении по схеме в интерпретации / для исходного состояния памяти d.V Посмотрим повнимательнее, чем замечательна интерпретация V. Множество значений (k, w) = FGiy (0, w0) дает множество {h} всех операционных историй схемы G, которое, как мы выяснили, полностью характеризует вычислительные возможности схемы. Только что доказанное следствие можно сформулировать еще одним способом. Лемма 2. Две схемы Gx и G2 функционально эквивалентны тогда и только тогда, когда множества их операционных историй совпадают. ' Формальная эквивалентность. Самое интересное в схемах Яно- ва это то, что множество операционных историй можно извлечь из схемы, не прибегая к понятию интерпретации. Опишем процедуру построения некоторых конструкций, которые мы назовем конфигурациями, для любой схемы Янова G(pu . . ., pk). Конфигурации по внешнему виду неотличимы от операционных историй, хотя строиться будут принципиально иным методом. Начальный шаг. Верхняя и нижняя последовательности пусты. Возьмем любой набор А0 = (olt . . ., ok) в качестве значений переменных ри . . ., ph, занесем его в верхнюю последовательность и перейдем к начальной вершине. Очереднойшаг. Пусть с набором А перешли к вершине S: а) если S — помеченный распознаватель, то мы попали в пустой цикл, построение конфигурации обрывается безрезультатно;
252 ГЛ. 7. ОПРЕДЕЛЕНИЕ СХЕМ ЯНОВА б) если* S — непомеченный распознаватель R с условием FCPi» · · -, Pk)* то помечаем /?, вычисляем ¥(А) и с тем же набором переходим к преемнику вершины R в соответствии со значением F(A); в) если S — останов, ставим в нижнюю последовательность символ останова pgj; построение конфигурации завершено; г) если S — оператор A^Pf), то помещаем Аь в нижнюю последовательность, а в верхнюю последовательность помещаем: произвольный набор Δ', образующий с набором Δ допустимую пару-(Д, Δ') для оператора A^Pj). Снимаем разметку распознавателей и с набором Δ' переходим к единственному преемнику оператора At. Только что описанный про'цесс является частным случаем важной общематематической конструкции, называемой порождающим процессом. Описание порождающего процесса очень похоже на описание алгоритма, и сам порождающий процесс похож на процесс вычисления. Важным отличием является то, что в некоторых: местах порождающего процесса есть точки неопределенности: (недетерминизма), в которых однозначный вычислительный акт заменяется актом произвольного выбора, правда, из некоторого точно описанного (в нашем случае даже конечного) множества. Из-за наличия точек неопределенности порождающий процесо создает («порождает») целое множество своих возможных исходов· Множество, задаваемое порождающим процессом, считается эффективно заданным множеством, так как возможность осуществить любо'й выбор в точках недетерминизма по соглашению при- гнается бесспорной. Легко понять, что алгоритм является частным случаем порождающего процесса, у которого единственная точка неопределенности — это произвольный выбор начальных данных для алгоритма. Вернемся к множеству K(G) конфигураций схемы Янова С Лемма 3. Множество конфигураций любой схемы Янова совпадает со множеством ее операционных историй. Включение в одну сторону следует из определения операционной истории, а в другую сторону вытекает из интерпретации V и относящейся к ней лемме 1.V Определение. Две схемы Янова Ολ(ρΐ9 . ♦ ., pk) α ^(jPi* · · ·» Pk) формально эквивалентны, если K(GJ = K(GJ. Из леммы 3 вытекает Τ е о ρ е м а 2. Две схемы Янова функционально эквивалентны тогда и только тогда, когда они эквивалентны формально. Замечательным свойством схем Янова является то, что вса три введенных вида эквивалентности
§ 7.3. ЭКВИВАЛЕНТНОСТЬ СХЕМ ЯНОВА 253 — функциональная (по результатам) — операционная (по истории вычисления) — формальная (по множеству всех возможных цепочек операторов, порождаемых схемой) оказываются равнообъемными. Истинная ценность этого обстоятельства, конечно, может быть осознана только в сравнении с другими разделами теоретического программирования. Для себя же мы воспользуемся этим обстоятельством лишь для того, чтобы сохранить за всеми тремя эквивалентностями одно обозначение ~ и взять за основу построения системы равносильных преобразований формальную эквивалентность, связанную с понятием конфигурации.
ГЛАВА 8 ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ § 8.1. Построение исчисления Исходные аналогии и догадки. Сравнивая схемы Янова с их гсрародителями — формулами исчисления высказываний, мы не можем не обнаружить значительное усложнение конструкций. Поэтому, хотя мы и стараемся следовать общей канве построения формальной аксиоматической теории, за редкими исключениями не может быть и речи о сколько-нибудь буквальном воспроизведении рассуждений, которыми мы руководствовались в повторительной главе о математической логике. Автор постарается ввести исчисление равносильных преобразований схем Янова некоторым, с его точки зрения, естественным образом, для того чтобы хоть как-нибудь показать читателю, как можно догадываться до подобного рода вещей. Однако, как уже отмечалось, экономия места и необходимость обеспечить поступательность изложения не позволит реставрировать реальный ход мысли создателей обсуждаемой теории, даже если бы автор опросил их самым подробным образом. Тайна открытия остается для каждого искателя спрятанной за замком с семью печатями, отпирать который ему суждено в одиночестве. Мы будем вводить правила преобразований как аксиомы или правила вывода, постулирующие элементарные и интуитивно независимые свойства схем Янова. Некоторые из этих свойств нам с самого начала стали известны в виде правил преобразований, например, перенос плюс-стрелки (рис. 7.7, а)) или расчленение дизъюнкции (рис. 7.4, б)), другие (например, понятие допустимых наборов) нам еще предстоит представить в виде удобного для работы правила, третьи еще только всплывут на поверхность при более детальной инвентаризации свойств. Попробуем, однако, навести в нашем хозяйстве некоторый порядок. Нам нужно построить такую систему преобразований, которая для всех преобразуемых друг в друга схем сохраняла бы наш главный инвариант — множество (корректных) конфигураций, создаваемых порождающим процессом, описанным в конце предыдущего' параграфа. Мы не случайно вставили слово «корректных». Дело в том, что наш порождающий процесс при свое*
§ 8.ί. ПОСТРОЕНИЕ ИСЧИСЛЕНИЯ 255 свободном развертывании создает существенно более широкое множество объектов. Это, во-первых, конечные цепочки операторов, упирающиеся в пустой цикл, и, во-вторых, бесконечные цепочки. С другой стороны, даже при такой «дополнительной» свободе действий порождающий процесс может не затрагивать всего того* что внесено в текст схемы. Наиболее очевидным примером являются изолированные вершины, т. е. такие части графа переходов, которые либо не достижимы от входа, либо от которых нет пути на останов, либо обладающие обоими недостатками вместе (рис. 7.10). Можно вообразить схемы, которые построены и работают в некотором смысле «наиболее экономно»: они содержат только «выполнимые» операторы и не совершают никаких «бесполезных» действий, т. е. таких, которые приведут к бесконечному движению по преобразователям и распозиавателям схемы. Если мы претендуем на построение, полного исчисления, мы должны обеспечить преобразуемость любой схемы в любую, ей эквивалентную, в том числе и обладающую подобного рода экономностью. Поэтому нам нужно иметь в исчислении какие-то правила, позволяющие обнаруживать, устранять, а когда надо и добавлять такие избыточные фрагменты схемы. В простейших случаях избыточные элементы схемы обнаруживают себя сразу. Очевидным правилом является такое: преобразователь с оператором, не имеющий входных дуг, недостижим и·может быть устранен. Другим очевидным случаем является ситуация, когда на вершину ведет плюс-стрелка от распознавателя с тождественно ложным условием. Эту ситуацию можно, однако, сформулировать в виде более элементарного независимого правила: распознаватель R с тождественно ложным условием можно заменить дугой, идущей от предшественника вершины R к преемнику вершины R по минус-стрелке. При этом плюс-стрелка от R исчезает вместе с самим R. В общем случае свойство элемента схемы быть «ненужным» не характеризуется им самим, а является свойством всей схемы в целом. Неработающий оператор может быть вершиной в изолированной компоненте графа переходов, а тождественность условия маскироваться цепочкой предшествующих или последующих проверок других условий. Можно легко сформулировать два достаточных условия. Вершина V графа переходов схемы Янова называется квазидостижимой, если в схеме существует путь от входной стрелки к V. Аналогично, вершина V называется квазипродуктивной, если в схеме существует путь от V к останову *). т — *) Читателю предлагается самостоятельно восстановить логическую связь •тих определений с формулированием достаточных условий недостижимости а непродуктивности вершин.
256 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ Материал первой части подсказывает нам, что так сформулированные свойства достижимости и продуктивности хорошо описываются в терминах прямого и обратного транзитивных замыканий: достижимая вершина принадлежит прямому транзитивному замыканию входной вершины графа переходов, а продуктивная вершина принадлежит обратному транзитивному замыканию останова. Важным отличием схем Янова является, однако, что в распознавателях преемники выбираются не произвольно, а предписанным условием способом. Таким образом, недостижимость вершины при построении конфигураций может оказаться замаскированной наличием пути от входной вершины, но содержащего распознаватели с противоречивыми условиями. В связи с этим в уже известные индуктивные процедуры построения транзитивных замыканий нам придется внести ряд поправок. Достижимость и допустимость. Займемся сначала достижимостью, при этом для начала полагая, что ни один из операторов не меняет ни одной предикатной переменной. Этот случай называется пустым распределением сдвигов. Начальный шаг: берем некоторый набор Δ значений предикатных переменных и метим им входную стрелку. Индуктивный шаг: пусть набор Δ метит входную дугу некоторой вершины V графа переходов. а) Если V — оператор, и его выходная дуга не имеет Δ в качестве пометки, метим ее набором Δ. б) Если V — распознаватель с условием F *) и ни одна из его выходных дуг не имеет Δ в качестве пометки, то метим набором Δ плюс-стрелку у V, если ¥(А) = t, и минус-стрелку — в противном случае. в) Если V — останов, ничего не делаем. Так описанная разметка оканчивается, когда ни на одном из индуктивных шагов нечего делать. Сделав такую разметку для каждого набора Δ, который можно подавать на входную стрелку, мы обнаружим, что каждая дуга графа переходов окажется помеченной некоторым множеством (может быть, пустым) наборов значений предикатных переменных. Вспомним из шестой главы, что любая^булев^ функция может быть представлена своим множеством истинности и, наоборот, любое множество наборов значений логических переменных может рассматриваться как множество истинности булевой функции. Тогда мы можем сказать, что вершина V графа переходов достижима тогда и только тогда, когда хотя бы одна из метящих ее входные дуги булевых функций не является тождественно ложной. *) Говоря о распознавателе с условием F, мы позволяем себе вольность не вводить для булевой функции, соответствующей формуле F, особого обозначения.
§ 8.1. ПОСТРОЕНИЕ ИСЧИСЛЕНИЯ 257 Как только мы это сказали, нам видно, что это свойство останется справедливым, если мы освободимся от ограничения пустого распределения сдвигов. Общий случай отличается от рассмотренного лишь тем, что если на входной дуге оператора А(Р) окажется набор Δ, то на его выходной дуге окажется целое семейство наборов {Δ'}, каждый из которых образует с Δ Допустимую пару (Δ, Δ')· Второе очевидное наблюдение состоит в том, что этот индуктивный процесс разметки множествами наборов (или, что то же самое, логическими формулами) нет необходимости делать для каждого входного набора в отдельности. Можно осуществить тотальный процесс, а именно: подать на входную стрелку полное множество наборов, т. е. тождественно истинную функцию, а на все остальные дуги — в качестве начального значения — тождественно ложную функцию. После этого трактовать каждый распознаватель R с условием F как сортировку: если по какому-то входу поступает множество наборов Ф, то тогда то множество, на котором F истинна, т. е. Ф&Ё, дизъюнктивно добавляется к функции, метящей плюс-стрелку у й, а множество наборов из •Ф, на котором F ложна, т. е. |F&0, дизъюнктивно добавляется к функции, метящей минус-стрелку у /?. Для того чтобы завершить это обобщение, нам надо разобраться в том, как выразить в терминах булев#ых функций роль операторов, которые являются источниками выходных наборов, образующих со входными допустимые пары. Пусть F — множество ΉβδοροΒ, поступающих на вход оператора А(Р). Напомним, что Ρ <Ξ {/?ι, . . ., pk}, a F — это функция F{pl9 . . ., pk). Пусть <Р — множество всех наборов Δ', образующих с каким-нибудь из наборов Δ из F допустимую пару. Рассмотрим любой набор <δ = σχ, . . ., oh и множество Var(6) наборов, получающихся из δ варьированием переменных из Р. Тогда, по определению, если <6^zF или, что то же самое, F(b) = f, то Var(6) cz φ. Далее, если Ρ(δ) = f, но в Var (δ) есть такой δ', что F(6 ) = t, то, по-прежнему, Var (δ) cz φ. Это очевидно, так как для любого δ' cz Var (δ) справедливо равенство Var (δ') = Var (δ). Если же для любого 6'cz;Yar (δ) имеет место F(S ) = f, то тогда наверняка Var (δ) f] f] Φ = 0. Отсюда получаем, если считать, что max(f, t) = t: Q) = maxF(p1 ph). Нам остается понять, как распорядиться информацией о разметке дуг схемы булевыми функциями, изображающими множества наборов, с которыми возможно прохождение данной дуги при порождении конфигураций. Как во всяком индуктивном процессе, мы можем воспользоваться информацией о разметке только после ее завершения. Условием завершения является насыщение
258 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ разметки, т. е. когда переносы логических наборов со входов на выходы не меняют уже стоящих там булевых функций. Поскольку при разметке имеет место только дизъюнктивное накопление, т. е, процесс, строго монотонный, насыщение обязательно наступит. Дазовем насыщенную разметку стационарной и пусть при ней некоторый распознаватель R с условием F имеет на плюс-стрелке функцию Ф. Из правил разметки следует: а) OQF, б) условие распознавателя В будет передавать управление по плюс-стрелке только на наборах, принадлежащих Ф. Отсюда следует, что в R условие F можно заменить на Ф. Смысл этого преобразования в том, что у множеств истинности условий схемы «срезаются» все недопустимые наборы, т. е. па которых это условие заведомо не будет вычисляться. Из-за этого, например, любое условие, передающее плюс-управление на недостижимый оператор, заменится тождественно ложным. Применяя правило устранения тождественно ложных условий, мы уберем входную дугу у оператора, после чего сможем убрать н сам оператор. Итак, мы видим, что свойство вершины в схеме Янова участвовать в процессе порождения конфигураций правильнее рассматривать в совокупности с множествами наборов предикатных переменных: вершина V называется достижимой, если существует непустое множество наборов Ф, допустимых для V, т, е. таких, с которыми вершина V проходится при порождении конфигураций. Продуктивность. Постараемся в аналогичных понятиях описать продуктивные вершины в схемах Янова. Определим процесс порождения остаточных конфигураций для любой вершины V в схеме и любого набора Δ предикатных переменных. Процесс порождения, остаточных конфигураций отличается от общего лишь начальным шагом, который в данном случае состоит в переходе к вершине F^c набором Δ. Мы скажем, что набор Δ является продуктивным для вершины V, если для этой пары существует остаточная конфигурация. Соответственно, вершина V в схеме называемся продуктивной, если множество Ψ ее продуктивных наборов непусто. Уже угадывается, что понятия допустимости и продуктивности исчерпывают проблему избыточных конструкций в схеме: вершина, являющаяся одновременно и достижимой и продуктивной,— это именно тот материал, который используется во множестве конфигураций схемы. Рассмотрим индуктивный процесс разметки дуг схемы Янова булевыми функциями, которые мы будем выбирать так, чтобы они накапливали нам для каждой вершины множества ее продуктивных наборов.
§ 8.1. ПОСТРОЕНИЕ ИСЧИСЛЕНИЯ 259 Начальный шаг. Очевидно, что для останова любой набор является продуктивным OFjsg = fy- именно эта функция метит все дуги, ведущие к останову. Шаг индукции для распознавателя. Пусть у распознавателя Щ¥) плюс- и минус-стрелки помечены соответственно Ψ+. и Ψ_, которые по предположению являются продуктивными наборами его преемников. Естественно, что для любого множества наборов Μ распознаватель может «пропустить» по плюс-стрелке только F&M, а по минус-стрелке — толькоПР&М. Отсюда получаем, что Ψβ = F&T+ (J ~~|F&¥_. В этом и только в этом случае F будет правильно сортировать множество своих продуктивных наборов между своими преемниками. Функцией Ψβ метятся все дуги, ведущие в Я. Шаг индукции для оператора. Пусть у оператора А (Р) выходная дуга помечена функцией Ψ. Очевидно, что любой набор Δ, для которого Ψ(Δ) = t, будет продуктивным не только для преемника оператора Л(Р), но и для него самого. Но тогда и любой набор А'е max Δ тоже будет продуктивным для Л(Р), так как ρ наборы (Δ', Δ) будут образовывать допустимую пару. Отсюда заключаем, что ^а(Р) = max Ψ ρ н этой функцией метятся все дуги, ведущие в А(Р). Очевидно, что везде под пометкой мы понимаем дизъюнктивное добавление метящих функций к тем, которые метили дуги в результате предыдущих шагов. Аналогично случаю достижимости посмотрим, как мы можем распорядиться информацией, полученной после насыщения разметкой дуг схемы. Рассмотрим любой оператор А схемы с его множеством Ψ продуктивных наборов. Если на его вход попадет непродуктивный набор, т. е. из ~\Ψ, то в этом случае мы знаем наперед, что процесс построения остаточных конфигураций при любом дальнейшем развитии не завершится результативно: он наверняка попадет в бесконечный цикл. Таким образом, любая работа с любым Δ^"~~|Ψ будет бесполезной. Эту бесполезную работу можно заблокировать, если поставить перед оператором А распознаватель #(Ψ) с плюс-стрелкой, ведущей на А, а с минус- стрелкой, поставленной на заглушку — простейший пустой цикл, имеющий вид распознавателя с условием f и обеими выходными дугами, ведущими на него же самого. В дальнейшем будем изображать заглушку (рис. 7.10, б) символом ®. Заметим, что блокирование движения с непродуктивными наборами не только предотвращает «ненужные» вычисления, но и делает непродуктивные наборы недопустимыми для соответствующих фрагментов схемы,
260 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ что может быть замечено на предмет их возможного удаления из> схемы. Очевидно, что такую же блокировку надо ставить и для входной стрелки. На рис. 8.1 и 8.2 показаны некоторые пары эквивалентных. схем Янова, преобразуемость которых опирается на понятия достижимости и допустимости (8.1) и (8.2) продуктивности. г) φ е) ж) Рис. 8.1. Преобразование с использованием понятия допустимости. а) Исходная схема, б) Стационарная верхняя разметка, в) Срезание недопустимых наборов, г) Ликвидация одного тождественного условия, замена другого на его отрицание, стационарная верхняя разметка, д) Срезание недопустимых наборов, е) Ликвидация тождественною условия, ж) Ликвидация оператора без входа. Перечень правил. Подведем некоторый итог. Наши правила* равносильных преобразований группируются по пяти категориям,, которые мы назовем: логические правила, топологические правила,
а) Исходная меж -лх n<J φ Стационарная нижняя размен/На с^ е) /локирование непродуктивных наборов г) Замена условий на ах о/нрнцанае с^> φ Перенос р/прелок е) Удаленно нерадоп/а/ощих раснознаваашей Рис. 8.2. Преобразование с использованием понятия продуктивности, а) Исходная схема, б) Стационарная нижняя разметка, в) Блокирование непродуктивных наборов, г) Замена условий на их отрицание, д) Перенос стрелок, е) Удаление неработающих распознавателей.
262 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ правила верхней разметки, правила нижней разметки, правила замены. Логические правила постулируют связь базисных булевых функций (ложь, отрицание, дизъюнкция) с правилами выбора плюс- и минус-направлений при вычислении условий в распознавателях. Это: (А1) удаление распознавателя с ложным условием, (А2) — правило отрицания (рис. 7.4, а) и (A3) — расчленение дизъюнкции (рис. 7.4, б). Топологические правила постулируют возможные изменения графа переходов. Это — (А4) правило удаления преобразователя, не имеющего входных дуг, (А5) перенос плюс-стрелок (рис. 7.7, а) и (А6) — правило одинаковости двух любых заглушек. Мы о нем не говорили, но необходимость его становится очевидной при некотором размышлении. Правила верхней разметки постулируют: (А7) — отсутствие наборов перед началом разметки, (А8) — допустимость любого набора значений предикатных переменных перед началом построения конфигураций, (А9) — правила распределения наборов по плюс- и минус-стрелкам при попадании на распознаватель и (А10) — свойства сдвига операторов как источника допустимых наборов. Правило (П1) «срезания» недопустимых наборов из множеств истинности условий в распознавателях позволяет реализовать информацию о допустимых наборах в условиях стационарной верхней разметки. Правила нижней разметки постулируют: (All) — отсутствие наборов перед началом разметки, (А12) — инициирование разметки, начиная с останова, перенос разметки с выходных дуг на входные (А13) при прохождении распознавателя и (А14) при прохождении преобразователя. Правило (П2) в условиях стационарности нижней разметки разрешает блокировать вычисления на .непродуктивных наборах. Правило замены (ПЗ) позволяет заменять вхождение логической формулы в схему на любую эквивалентную логическую формулу. Правило подстановки (П4) посту- равносильности при замене некоторой части Ш(нв2) Рис. 8.3. Пример фрагмента^ лирует сохранение схемы на равносильную. Нам остается ввести метаязык для изображения найденного исчисления. Исчисление будет состоять из схем аксиом (А1 — А13) и правил вывода (Ш — П5). Аксиомы и утверждения правил
§ 8.1. ПОСТРОЕНИЕ ИСЧИСЛЕНИЯ* 263 вывода изображаются в виде где ~ — знак равносильности, a <Fi и <F2—некоторые фрагменты схемы Янова. Фрагментом схемы G называется некоторая часть Мш9 г .Ά4) •Ф ,A7)\~\f AB^rJ^t Aff)(£ Viva*,? yyiock^f Τβ Учж(р) Л1) Г. (тм(р)=г) Рис. 8.4. Исчисление равносильных преобразований. а) Логические правила, б) Топологические правила, в) Правила верхней разметки. (подграф) схемы G, для которой (части) указана ее связь с остальными вершинами схемы G. Эта связь указывается в виде входов и выходов фрагмента. Выходы фрагмента — это размеченные дуги, показывающие, какие вершины фрагмента соединены с остальны-
2G4 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ ми вершинами схемы. Входы фрагмента — это размеченные стрелки, показывающие, к каким вершинам фрагмента ведут дуги от остальных вершин схемы. Фрагменты могут быть конкретными и обобщенными. В обобщенных фрагментах вместо конкретных условий и операторов стоят метапеременные, чьими значениями являются произвольные (или с указанными ограничениями) логические формулы, операторные символы и их сдвиги. Кроме этого, If фшфшц |jf Ιί^-д mm \ к к fy fY Ik ¥ vmax(fi) а) \(хъ.§ы-\кьу=<1>) Si W П2) Υ ' p }e /■v Μ α=β F(<x)~F(P) ΙΪ4) д) Ff~Fz> Ъ(Ь)~Ь Рис. 8.5. Исчисление равносильных преобразований (окончание), г) Правила нижней разметки, д) Правила замены. в обобщенных фрагментах могут быть так называемые обобщенные входы., которые указывают, к какой вершине может вести произвольная (в том числе и пустая) совокупность дуг, выходящих либо от остальных вершин схемы, либо (если это не запрещено специальной оговоркой) от выходов этого же фрагмента* Обобщенные входы указываются жирными стрелками, входы (любые) метятся римскими цифрами, выходы — арабскими цифрами. Условия и метящие булевы функции записываются в виде логических формул. Сделанные определения поясняет пример фрагмента на рис. 8.3. В нем указывается, что к верхнему распознавателю обязательно
§ 8.2. КОРРЕКТНОСТЬ ИСЧИСЛЕНИЯ 265 подходит некоторая дуга. В оператор А извне могут входить любые дуги. В нижний распознаватель помимо входной стрелки могут вести извне любые дуги, но среди них не может быть ни одна из выходных дуг фрагмента, помеченных цифрой 2. Пометка двух выходных дуг одной и той же цифрой означает, что обе эти дуги должны вести; к одной и той же вершине схемы. Исчисление равносильных преобразований схем Янова изображено на рис. 8.4 и 8.5. В посылках правил Ш и П2 символ у означает квантор всеобщности, с помощью которого формулируются утверждения вида V (Т)(Р), звучащие в данном случае следующим образом: «для любого объекта вида Т, который можно усмотреть в преобразуемой схеме Янова, удовлетворяется свойство Р». § 8.2. Корректность исчисления Справедливость логических и топологических аксиом после их содержательного обсуждения в предыдущем параграфе очевидна и не требует дополнительных рассуждений. Верхняя разметка. Рассмотрим цравила верхней разметки. Из аксиом видно, что при верхней разметке дуг схемы единственным безусловным источником наборов значений предикатных переменных является входная стрелка. Аксиома А9 переносит на выходные дуги распознавателя лишь те наборы, которые поступают на его вход. Аксиома А10 порождает лишь те наборы, которые могут получиться из наборов, поступающих на вход оператора, применением операции взятия максимума (заметим, что max (f) = f для любого Р). Таким образом, если в результате ρ применения аксиом А7 — А10 на дуге s, ведущей к некоторой вершине V схемы, появилось множество наборов φ, то это значит, что каждый из этих наборов мог появиться на дуге лишь в результате применения аксиом А7 — А10 к цепочке фрагментов схемы, образующих путь от входной стрелки до вершины V Рис. 8.6. Путь верхней разметки. (рис.. 8.6). Более точно это формулируется так: для любого Δ, такого, что φ(Δ) = t, существует путь в схеме от входной стрелки до вершины V, образованный вершинами Vu . . ., V, и дугами» помеченными функциями φ1? . . ., <рг, где Fr = F, (Pi=t, <рг = <р>
266 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ а также существует последовательность наборов Δ1? . . . . . ., ΔΓ = Δ, удовлетворяющие следующим требованиям: 1) Φι(Δ,) = t, 2) если Vi (1 <1 ί ^ г — 1) — распознаватель с условием F, то Δη-χ = Δ*, причем F(A|) = t, если Vt соединен с Vi+l плюс- стрелкой, и F(Ai) = f в противном случае; 3) если Vt (1 <I i ^ г — 1) — преобразователь с оператором А(Р), то Δί+ι отличается от Δ ^ не более чем значениями переменных, принадлежащих Р. Мы уже указывали, что набор Δ называется допустимым для вершины V схемы, если в процессе порождения конфигурации (§ 7.3) возможен переход к вершине V с набором Δ. Только что проведенное рассуждение доказывает допустимость для V любого набора, принадлежащего функции φ, метящей какой-либо вход вершины V. Назовем множество Фу всех допустимых наборов для вершины V полным условием работы этой вершины. Нами доказана Л е м м а 1. Если к вершине V подходит дуга с пометкой φ, то φ =э Фу. Непосредственно из вида аксиом А9 и А10 вытекают такие леммы Лемма 2. Если плюс- и минус-стрелки распознавателя с условием F помечены функциями β+ и β_ соответственно, то P+=dF, β+&β_==Ξί и Ρ&β_ = ί. Лемма 3. Если к распознавателю в обозначениях леммы 2 подходят т дуг, помеченных функциями <рх, . . ., фт, то β+V β-=>Φι V ... V Фт- Л е м м а 4. Если к оператору А(Р) подходят т дуг, помеченных функциями ц1у . . ., <рш, и выход оператора помечен функцией β, то Ргэтах(ф! V·.. V Фт). ρ Назовем состояние схемы Янова, при котором выполнена посылка правила вывода Ш, стационарной верхней разметкой. Это название, уже употреблявшееся неформально в предыдущем параграфе, оправдано тем, что в условиях стационарной разметки никакое дальнейшее применение аксиом А9 и А10 не изменит верхней разметки дуг ехемы. Очевидна Лемма 5. В условиях стационарной верхней разметки и s обозначениях лемм 3 и 4 для любого распознавателя p+VM^iV-V4
§ 8.2. КОРРЕКТНОСТЬ ИСЧИСЛЕНИЯ 267 и для любого оператора А(Р) Р=тах (φ! Λ' · · · 7\ Фт). Р Смысл правила П1 устанавливает следующая Лемма 6. В условиях стационарной верхней разметки для любого распознавателя R с пометками на его выходных дугах β+ и β_ β+νβ-^Φ*. Доказательство. Импликация β+ V β- ^ ®r вытекает из лемм 1 и 5. Докажем импликацию ΦΛ:ζ>β+\/β-· Пусть набор Δ является допустимым для распознавателя R. Это значит, что существуют путь движения от входной стрелки к вершине V через вершины Vl9..., Vr=R и такая последовательность наборов Δχ, . . . . . ., Аг=А,чтопри движении по схеме к вершине Vt подходили с набором At (£=1, . . ., г). Пусть теперь в пути через вершины V-L, . . ., Vr проходимые входная стрелка и дуги в условиях стационарной разметки помечены функциями φχ, . . ., φΓ . Покажем по индукции, что φέ(Δ^)=1 (i = 1, . . ., г). Для i = i это очевидно, так как (p^t. Пусть φ,_1(Δ,_1)=Ι.' (1) Пусть Vi-г— распознаватель с условием F и с пометками β+ π β_ на выходных дугах. В этом случае Δ» = Δ,_1. (2) В силу стационарности разметки φ^^β+νβ-? значит, в силу (1) p+(Ai_1)VP-(Ai-i)=t. ' (3) Если F(Ai_1)=t, то Φι=Ρ+ (4) и в силу леммы 2 не может быть, чтобы β_(Δί__1)=ί. Значит, в силу (3) β+ίΑ,-χΗΙπ в силу (4) и (2)<p4(AO=t. Если F(A,-1)=f, то φ^β_ и, рассуждая аналогично, по лемме 2 и (2) получим также, что <p,(Af)=t. Пусть V1_г— преобразователь с оператором А(Р) с пометкой на выходе. Пусть /Δ — функция, для которой Δ является ее множеством истинности. Поскольку Δ^-ι и Δ$ отличаются не более чем значениями переменных из Р, то max/Ai_1(A,) = t. (5) ρ Но в силу (1) inax /лг_1 => шах фг—ι (6) Ρ Ρ
268 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ и в силу стационарности maxcpi_i => Фг, Ρ откуда в силу (5) и (6) получим, что φ/(Δί)=4. Взяв доказанное утверждение индукции для i=r, получим, что <pr(A)=t; отсюда по лемме δ доказывается требуемая импликация, а с ней и лемма 6. V Нижняя разметка. Рассмотрим теперь правила нижней разметки. Лемма 7. В условиях стационарной нижней разметки для любой вершины V схемы G функция^V, метящая входы вершины V, тождественна функции Ну, истинной на множестве продуктивных наборов для V. Д оказательство. Утверждение леммы в части импликации / Uv zdWv очевидно, так как любая последовательность вершин от V к СхЗ и та последовательность наборов, с которыми эти вершины проходятся при построении любой остаточной конфигурации, продуцируемой набором Δ и вершиной V, взятые вместе и прочитанные в обратном направлении, задают последовательность применения аксиом All — А14, создающих разметку на входе F, включающую набор А. В силу стационарности любая последовательность будет заведомо реализованной. Пусть теперь, наоборот, известно, 4To4V(A)=t. Тогда существует последовательность S вершин схемы V=V19 72, . . ., V, =121 и последовательность функций метящих дуги между этими вершинами, обладающие следующим свойством: для любого отрезка Σ последовательности, образованного одними только распознавателями и ограниченного либо операторами, либо (слева) началом, либо (справа) остановом: существует реализующий набор А, принадлежащий всем метящим множествам из отрезка Σ, и который, будучи поданным на начало Σ, пройдет в графе переходов по вершинам, образующим Σ. При этом: (1) если началом последовательности S также является отрезок распознавателей Σ0, то А может быть его реализующим
§ 8.2. КОРРЕКТНОСТЬ ИСЧИСЛЕНИЯ 2G9 табором; {2) если отрезки Σ и Σ' разделяются оператором А(Р), то наборы Δ и Δ', реализующие эти отрезки, образуют пару (Δ, Δ'), допустимую для А(Р). Сделанное утверждение, которое является перефразировкой правил применения аксиом All — A14f >€разу дает конструкцию остаточной конфигурации, продуцируемой набором Δ и вершиной У. V Л е м м а 8. В условиях стационарной нижней разметки лю- >6ое применение правила П2 корректно. Доказательное рассуждение уже проведено в предыдущем па- ;раграфе при введении понятия нижней разметки, ν Отношение равносильности. Заметим, что поскольку схема iB целом является частным случаем понятия фрагмента, правила ПЗ и П4 позволяют выводить соотношения равносильности для •схем.Свойства равносильности как бинарного отношения выражает Лемма 9. Отношение равносильности рефлексивно, симметрично и транзитивно. Доказательство. Рефлексивность следует из правила ПЗ при одинаковых α и β. Симметричность следует из правила П4, если в качестве посылки взять следующие соотношения: Доказательство транзитивности требует в качестве посылки соотношения Но симметричности эту посылку можно переписать в виде I откуда но правилу Π 4 вытекает, что 5*"ι~<?Υ V Формальную возможность трактовать рассмотренную аксиоматику как правила преобразования схем предоставляет Лемма 10 (правило подстановки). Если #"(ri)~W2)· Доказательство. Взяв в правиле П4 в качестве подсылки Ρι~9~» *"(*"i)~Wi), юолучим, что8Г(Фт^~&ш(&я1)9 откуда в силу симметричности выте- жает утверждение леммы. V Замечание. Свойство симметричности в соединении с правилом подстановки гарантирует обратимость системы преобразований, задаваемой аксиоматикой. Справедливость правила П4 была установлена при неформальном обосновании аксиоматики в предыдущей главе.
270 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ Проведенное выше содержательное изучение исчисления равносильных преобразований резюмирует Теорема 3. Любые две равносильные операторные схемы Янова эквивалентны. § 8.3. Канонические схемы га технические теоремы Канонические схемы. Схема Янова G(px, . . ., pk) с операторами Ах, . . ., Ап называется матричной, если она содержит (п+1)2 распознавателей Ягу(¥и) (i=0,. . ., η; /=1, . . ., n+i)r один распознаватель — заглушку (g), соединенных следующим образом: 1. Каждый распознаватель Rtj имеет один вход. 2. В распознаватель R0l ведет входная стрелка, в распознаватель Ru (i = l, . . ., η) ведет выходная дуга оператора А^. 3. Плюс-стрелка распознавателя Rij(i=0, . . ., п;у=1, . '. ., п) ведет к оператору А;, а минус-стрелка — к распознавателю 4. Плюс-стрелка распознавателя Дг-,п+1 (ί=0, . . ., η) ведет к останову, а минус-стрелка к заглушке ®. 5. Условия Fi7· (i=0, . . ., η; /=1, . . ., п-\-1) удовлетворяют соотношениям π л тг Fij" если 7'1 = 7*2' If, если 7х=т^ 72- 6. Каждое условие есть или f или имеет вид дизъюнктивной совершенной нормальной формы. Оператор А схемы G называется выполнимым, если существует конфигурация схемы G, содержащая А. Канонической схемой Янова называемся матричная схема, все операторы которой выполнимы, и в которой все условия истинны только на своих допустимых и продуктивных наборах. Пример канонической схемы Янова (эквивалентной примеру с рис. 7.9) указан на рис. 8.7. Две схемы Янова называются равными, если они сравнимы, их графы переходов изоморфны, имеют одинаковое распределение плюс- и минус-стрелок, а соответственным вершинам сопоставлены одни и те же операторы и условия. . Специфические свойства канонических схем устанавливает Теорема 4. Если две канонические схемы Янова не равны\ то они не эквивалентны. Доказательство. Если неравные канонические схемы содержат неравное количество операторов или неодинаковые операторы, то множества конфигураций этих схем не будут совпадать в силу выполнимости каждого из операторов. Таким образом,
§ 8 3. КАНОНИЧЕСКИЕ СХЕМЫ И ТЕХНИЧЕСКИЕ ТЕОРЕМЫ 271 остается рассмотреть лишь сравнимые схемы Gx и 6?2, содержащие одинаковый набор? операторов А1? . . ., Ап. Если такие схемы не равны, то это значит, что существует такой набор Δ и такой распознаватель Ru, что F(i],(A) = t (1) и T$(A) = t, (2) где Fjj* nFif — условия, сопоставленные Rtj в схемах Gt и G2 ш>НШШ ш^< Рис/8.7. Каноническая cxeivfa Янова. соответственно. В силу (1) набор Δ является допустимым и продуктивным для распознавателя Л^. Это значит, что для Gx существует конфигурация, начало которой имеет вид At . . . ΔΓ Δ (3) Ait .. . Air ). Если для схемы G2 не существует конфигурации, начало которой имеет вид (3), то неэквивалентность Gx и 6?2 доказана. Пусть 6?2 также имеет конфигурацию, начало которой- равно (3). Тогда, очевидно, в силу (1) и в силу свойства 5 матричных схем в схеме Gx после символа At в рассматриваемой конфигурации окажется символ A j (или останов, если 7=^+1), а в схеме G% *) Здесь Л. — операторный символ оператора А^.
272 ГЛ 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ окажется наверняка не символ А^ Это утверждение завершает доказательство теоремы 4. VV Технические теоремы. Очевидно, что основным применением построенного исчисления будет доказательство возможности 77/ ^8)n<jU) γ/ ί 2 ill 773л Й^../ * / (J) / ψνβ) TT11 Если α&.β=/, та Д"не1) пи 1 1 ί ιΤ4 Тсс) г\-/ Ш (а) / 2 1 21 £ ТТ6 @™{{а) ^ (^^(К^У^^б ΤΤδ {αγκ пи (ос TTW Если ocScp=ffmo \Ι ι/ /.<?-/ 2 Рис. 8.8. Технические теоремы. построить для любой схемы Янова равносильную ей каноническую схему. Для этой цели потребуется целая серия дополнительных
§ 8.3. КАНОНИЧЕСКИЕ СХЕМЫ И ТЕХНИЧЕСКИЕ ТЕОРЕМЫ 275 ТТЬ пз г ι * дд Аг V-*-г\ А3 г~\ А2 А rv^ (Ί{-\α&.-\β)) n^> ftavjjn <^-> ha) r^> (a) 12 1 2 1 <?/W;@ 12 1 г I .1 r\ J\ J\ Τ~\ Α ι 7 / (V) / (ί#) / ; 111 / / / / A' ' К 772* A & Г\ ТТЗ A A / * ® \7 © 12 12 A ^ A / ^ / / / fftfTj rx^ f (a&fivcckijl·) j /7* ( (*)» r£ //J ? \ ~ G£) 77? i?-^-f,\ га* Рис. 8.9. Доказательства технических теорем (ТТ1—ΤΤδ).
274 ГЛ. ,8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ /7044: 1 2 (β) 2 / ί Πδ,Α1 ^ пи 0. / 2 TTS-Б: (fe & ffo Ά /Qa & (& & 0 7 1 / Пв-В: (а A2 nu ir\a\ ТТ6-6 , пи 0 ГГ,Г: (£) ^УЩ ns-B(\-^ ττβ-Б пи ( (ay гч; 0 Рис. 8.10. Доказательства технических теорем (ТТ6—ТТ8).
§ 8.3. КАНОНИЧЕСКИЕ СХЕМЫ И ТЕХНИЧЕСКИЕ ТЕОРЕМЫ 275 TTW: [a) r<j **» /ν; Ψ^ /Μ/' (β) (л) ) 2 ψ) 2 (JVa] 2 J 2 3 7' (J) - f \fi) 'f Ш ТТ9,ПЗ Д. T7J Лч ТЩА Л. ТТ9* Л. n^j МП r^J (β) ry · [β) r^f (jffj 2 Qva) 2 (jva) 2 {βνα) 2 [*) 2 J 2 J ill \I1 if/ · |/ \II TT11: _ Л\ Л*. /4\ ЩМ* A A5_ ^ > (y&fi) J Q > ^ 2 2 J / * JL /) / / * Рис. 8.11. Доказательства технических теорем (ТТ9—ΤΊΊ1).
276 ГЛ 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ правил преобразования, которые будут ниже упоминаться под названием технических теорем (ТТ). Каждая техническая теорема имеет вид выводимого соотношения равносильности между некоторыми фрагментами $FX и ^"2; формулировки одиннадцати технических теорем приведены на рис. 8.8. Доказательства этих теорем, приведенные на рис. 8.9 — 8.11 имеют вид цепочек равносильностёй, начинающихся и кончающихся фрагментами ЗГХ и <?% соответственно. Над каждым знаком равносильности указывается ссылка на аксиому, правило вывода, ила ранее доказанную техническую теорему, в силу которой справедлива данная равносильность. Ссылка, помеченная звездочкой, сзначает применение аксиомы или теоремы в инверсной форме, т. е. когда правая часть соотношения равносильности, образующего утверждение, заменяется на левую. Единственное доказательство, которое, быть может, требует дополнительных замечаний, — это теорема ТТ6-Б. Поскольку •фрагмент, о котором идет речь в теореме, не имеет входов, разметка его, сделанная по аксиоме А7, будет инвариантна по отношению к любому вхождению этого фрагмента в какую бы то ни было схему. Поэтому применение правила П1 допустимо. Дадим наперед несколько топологических определений. Последовательность распознавателей Rl4 . . ., Rt в схеме дазывается цепочкой, если Rt имеет i?j+i своим преемником (i=l, . . . . . . , t—1). Цепочка называется правильной, если каждый распознаватель из цепочки имеет только один вход. Замкнутая цепочка {Rt соединен с Нг) называется циклом. Распознаватель, у которого один из выходов является одновременно его входом, называет· ся полуциклом. § 8.4. Полнота исчисления Основу данного параграфа составляет Теорема 5. Для любой схемы Янова G существует равносильная ей каноническая схема GK. Доказательство теоремы будет дано в виде алгоритма преобразования схемы G в схему GK путем последовательного применения аксиом, правил вывода и рассмотренных выше технических теорем. Формирование цепочек. 1-й шаг. Стандартизация распознавателей. По правилу ПЗ условие в каждом из нетождественно ложных распознавателей записывается в совершенной нормальной дизъюнктивной форме, а затем по аксиоме A3 все распознаватели расчленяются так, что условие в каждом распознавателе имеет вид элементарной конъюнкции (заметим, что любые элементарные конъюнкции δι и 02 либо равны, либо ортогональны^ т. е. 6i&02=f).
§ 8.4. ПОЛНОТА ИСЧИСЛЕНИЯ 277 2-й шаг. Перенос плюс-стрелок. Определим процесс пере- воса плюс-стрелок каждого из распознавателей R схемы по следующему правилу: а) если R — заглушка, стрелка не переносится; б) если R — полуцикл, применяется теорема ТТ7; в) если плюс-стрелка от R ведет к преобразователю, останову или заглушке, стречка не переносится; г) если плюс-стрелка от R(a) ведет к распознавателю Λ(β), то применяется аксиома А5, если α=β, и ТТ11, если α&β=ϊ. Будем последовательно применять эти правила к каждому из распознавателей схемы. Кроме того, если какой-либо из распознавателей в силу переноса стрелок окажется без входа, то он сразу же уничтожается по теореме ТТ6. При переносе плюс-стрелки могут встретиться два случая: А. Перенос стрелки обрывается естественным образом в соответствии с правилами а) и в). Б. Стрелка от R(a) после последовательности переносов через распознаватели i?!,..., Rt (£>1) опять вернулась на* вход Rx. -Это означает, что распознаватели #!,..., Rt образуют цикл. В этом случае рассмотрим распознаватель /?ι(β). Если β=α, то плюс-стрелка от R^a) идет нагерияка вдоль дикла. Забудем на время плюс-стрелку от R(a) и начнем переносить плюс-стрелку от /?χ(α). Естественно, что она пройдет ту же последовательности переносов, что и вначале стрелка от /?(оь), *г. е. после серии переносов плюс-стрелка от /?ι(α) попадает на вход /?χ(α). Таким образом, /?χ(α) станет полуциклом, который по теореме ТТ7 трансформируется в заглушку. Плюс-стрелка от /?(а) переносится на эту заглушку, которая по аксиоме А6* раздваивается, после чего для порядка восстанавливается первоначальный вид распознавателя /?ι(α). Пусть β&α==ί. Тогда α&~~]β=<* или Πβ=α\/7» гДе γ ~ некоторая совершенная нормальная форма. Применим к βχ(β) аксиому А2. Очевидно, что нлюс-стрелка от RiC~}$)=Ri(ol\/y) пойдет вдоль цикла i?t , . . ., Rt. Применив к Й^аЦу) аксиому A3, сведем дело к предыдущему случаю, после чего опять восстановим распознаватель Rx(a\/y) к виду /?ι(β). Таким образом, мы добились того, что у каждого распознавателя, не являющегося заглушкой, плюс-стрелка направлена или в заглушку, или в преобразователь, или в останов. 3-й шаг. Ликвидация циклов по минус-стрелкам. Очевидно, что после 2-го шага, если только в схеме остались циклы, то распознаватели Rly . . ., Rtr образующие эти циклы, соединены друг •с другом только минус-стрелками. Если ί=1, то такой полуцикл, ликвидируется по теореме ТТ8. Рассмотрим сначала правильный цикл Ru . . ., Rt, т. е. цикл, яе имеющий входов извне. В этом случае мы применим к кг(а)
278 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ аксиому А2 и расчленим по аксиоме A3 """]<* на элементарные конъюнкции. Все возникшие при этом плюс-стрелки будут вести к распознавателю i?2(P)· По правилам шага 2 осуществим перенос этих плюс- стрелок. В результате Д2(Р) окажется без входных дуг й может быть уничтожен по теореме ТТ6. Поскольку /?1? . . ., Rt — правильный цикл, вслед за П2 могут быть последовательно уничтожены все распознаватели, входящие в этот цикл, равно как и распознаватели, возникшие при расчленении Нг. Рассмотрим теперь любой цикл Ru ..., Rt, имеющий извне I входов. Возьмем любой из этих входов. Если этот вход идет от распознавателя, то после 2-го шага доказательства это может быть только минус-стрелка некоторого распознавателя R(a). Если вход идет от преобразователя, то по аксиоме А1* можно между ним и циклом вставить распознаватель R(i). Применим к распознавателю Λ (α) аксиому А2 и по аксиоме A3 расчленим его на элементарные конъюнкции. Все возникшие при этом плюс-стрелки будут входить в тот же распознаватель R^l^i^t), в который ранее входила минус-стрелка от Λ (α). По правилам шага 2 осуществим перенос всех плюс-стрелок с распознавателя Rt. Естественно, что по окончании переноса ни одна из этих плюс-стрелок не будет соединена ни с одщш из распознавателей Ru . . ., Rt. Таким образом, теперь цикл Ru ..., Rt будет иметь Z—1 вход. Повторяя описанный процесс ликвидации входов в цикл I раз,получим в конце правильный цикл, который можно будет уничтожить по правилам предыдущего абзаца. 4-й шаг. Ликвидация многих входов у распознавателей. Рассмотрим любой распознаватель R. Поскольку в схеме нет циклов, для него всегда существует цепочка, ведущая от R либо к преобразователю, либо к останову, либо к заглушке. Длина h(R)^0 максимальной такой цепочки конечна. Назовем h(R) высотой R. Очевидно, что если от Я к некоторому R' ведет дуга, то h(R)>h(R'). Рассмотрим теперь в схеме распознаватели, имеющие более одного входа, с максимальным значением высоты hmax, и применим к ним теорему ТТ4. В результате мы получим схему с максимальным значением высоты, равным hmax — 1. Осуществляя последовательно этот процесс размножения распознавателей по теореме ТТ4, мы в конце концов получим схему, в которой все распознаватели, отличные от заглушек, будут иметь только по одному входу. Ликвидация нескольких входов в заглушки (не считая, конечно, входов, идущих от них самих же) делается но аксиоме А6*. Окончательная канонизация. 5-й шаг. Стандартизация цепочек. После 4-го этапа уже можно заметить некоторое сходство преобразуемой схемы с канонической. На рис. 8.12 показан результат 4-го этапа для исходной схемы с рис. 7.9. Все распо-
§ 8.4. ПОЛНОТА ИСЧИСЛЕНИЯ 279 внаватели схемы сгруппированы в правильные цепочки, соединенные минус-стрелками. Входов цепочку идет либо от входной стрелки, либо от преобразователя. Минус-стрелка последнего распознавателя ведет либо к преобразователю, либо к останову, либо на заглушку. Сначала добьемся того, чтобы число цепочек в схвхме в точности равнялось тг+1, где η — число операторов. Для этого, если входная стрелка схемы или выходная дуга преобразователя непосредственно ведет к какому- либо преобразователю, применим к ней аксиому А1*, причем плюс-стрелка вставленного распознавателя R(i) ведет, для определенности, на останов. Теперь сделаем так, чтобы минус-стрелка s последнего распознавателя каждой цепочки вела на заглушку. Если s ведет к преобразователю, то по аксиоме А1* вставим на ее место распознаватель R(i) с плюс- отрелкой, ведущей на заглушку. Применяя аксиому А2, заменяем R(i) на R(t) с плюс- стрелкой, ведущей на оператор, и с минус-стрелкой, идущей на заглушку, и затем расчленяем if(t) по аксиоме A3 на элементарные конъюнкции. Для обеспечения ортого- Рис. 8.12. Схема перед стандарти- нальиости, пользуясь теоремой зацией. цепочек. ТТ10, сгруппируем распознаватели вдоль каждой цепочки так, чтобы все распознаватели с одинаковыми элементарными конъюнкциями стояли рядом, образуя цепочку g. Применяя теоремы ТТЗ и ΪΤ6, уничтожим все распознаватели, кроме первого, в каждой цепочке g. Теперь добьемся того, чтобы в каждой из п-\Л цепочек присутствовали передачи управления на каждой из η операторов и на останов. Для этого по аксиоме А1* вставим в любом месте цепочки распознаватель R(i) с плюс-стрелкой, ведущий на недостающий преобразователь. После этого по теореме ТТ10 упорядочим распознаватели вдоль цепочки в соответствии с нумерацией операторов, т. е. BvTaKOM порядке: Аг , . . ., Ап, останов, заглушки. В результате этого упорядочивания все распознаватели с плюс- стрелками, ведущими на заглушки, сгруппируются в конце цепоч-
280 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ ки. По теореме ТТ5 сделаем все заглушки вполне одинаковыми с условием, равным f, и по аксиоме А6 соберем все заглушки r одну. В результате на концах цепочек смогут появиться распознаватели, обе выходные дуги которых ведут .в одно место. Устраним эти распознаватели по теореме ТТ2. Наконец по аксиоме A3* в каждой цепочке сгруппируем в один распознаватель все= элементарные конъюнкции, ведущие к одному и тому же оператору. В результате шагов 1—5 мы получим матричную схему 6?м» равносильную исходной схеме G. 6-й шаг. Обеспечение выполнимости. Добьемся сначала того, чтобы условия воех распознавателей равнялись единице· только на допустимых наборах. Для этого с помощью аксиом А7 — А10 построим стационарную верхнюю разметку схемы Gm и затем применим правило П1 к каждому из распознавателей. Поскольку теперь для каждого R(F) имеет место FiDOft(F), желаемое достигнуто. Применением аксиом А7* — АЮ* разметка снимается со схемы. После этого по аксиоме А1 вычеркнем из схемы все распоз- паватели вида /?(f). В результате этого в схеме могут появиться. операторы, не имеющие входов. Вычеркнем эти операторы по аксиоме А4 и вслед за ними по теореме ТТ6 выходящие из них цепочки распознавателей'. Осуществим теперь с помощью аксиом All — А14 стационарную нижнюю разметку и с помощью правила 112 заблокируем все^ движения по схеме с непродуктивными наборами. По аксиоме А6 соберем все новые заглушки в одно место. Снова осуществим стационарную верхнюю разметку и применим правило П1 к каждому из распознавателей. Удалим распознаватели с тождественно ложными условиями и, если окажутся, операторы без входов. Поскольку в результате блокировки все непродуктивные наборы стали недопустимыми, после этого- шага все распознаватели будут истинны только на допустимых и продуктивных наборах. В результате изолированные фрагменты схемы, если они и остались, имеют вид правильных циклов, образованных одними операторами. Рассмотрим любой такой цикл и по аксиоме А1* заменим одну из его дуг (А^, А^) распознавателем R(i)c минус-стрелкой, идущей на А;-, а с плюс-стрелкой, идущей на заглушку. По аксиоме А2 заменим его па R(t), у которого на заглушку будет теперь идти минус-стрелка. Осуществив стационарную верхнюю разметку в этом фрагменте, применим к R(t) правило П1, в результате чего он приобретет вид R(i). Убрав его по аксиоме А1, мы обнаружим, что выход из At идет на заглушку, а А;- остался беа входа. Разомкнув таким образом цикл, мы сможем, применяя аксиому А4, начиная с А7-, устранить весь изолированный фрагмент.
§ 8.5. ЕЩЕ ОДИН ИСТОРИЧЕСКИЙ ОБЗОР 281 В случае необходимости после этой процедуры повторяется «стандартизация цепочек распознавателей, реставрирующая матричный вид схемы. Теорема 5 доказана. VV Теорема 6 (о полноте). Любые две эквивалентные схемы Янова равносильны. Доказательство. Пусть Gt~Gt. (1) По теореме 5 для схем Gx и G2 существуют канонические схемы <?к) и G^k соответственно, для которых d-G^' и Gt~G%> (2) Очевидно, что C№ = G%> = GK, (3) так как если бы Gk ¥=Gk, to тогда в силу теорем 5 и 4 мы пришли бы к противоречию с (1). Таким образом, (2) переписывается в виде G1~GK и G2~GK, откуда по симметричности и, транзитивности отношения равносильности получаем, что Gt~G2. VV §8.5. Еще один исторический обзор Схемы программ А. А. Ляпунова. А. А. Ляпунов, внесший большой вклад в формирование программирования как научной дисциплины, был одним из первых математиков, разработавшим в начале 50-х годов символику программирования, сохраняющую и поныне значимость принципиальных своих положений. Важнейшим понятием, введенным А. А. Ляпуновым, было понятие оператора, являющегося одновременно и единицей действия и -единицей конструирования программы. Как единица действия оператор выполняет некоторое преобразование содержимого памяти машины, т. е. отображает одно состояние памяти на другое. Это .и объясняет название «оператор». Как единица конструирования программы оператор имеет некоторое обозначение, показывающее тип оператора, его место в программе, и конкретное содержание оператора (спецификация). Важным свойством оператора было то, что трактовка оператора как единицы действия носит относительный характер. Два оператора А и В, выполненные друг за другом, осуществляют какое-то совокупное преобразование состояния памяти, т. е. также образуют некоторый оператор С. Для того чтобы операторы А и В выполнялись подряд, их надо в программе поместить один за другим: А В. Их связь с оператором С выглядит тогда таким образом: С — АВ, а информация, например, о том, что А и В можно выполнять в любом порядке, получая один и тот же результат, может быть выражена равенством А В = В А. Выражаясь языком алгебры, можно сказать, что операторы программ образуют полугруппу, в которой могут существовать определяющие отношения. Изучение полугруппы операторов приобрело фундаментальную роль в теоретическом программировании. Аналогия двух рядом стоящих операторов А В с произведением двух чисел делала понятными такие обозначения, введенные А. А. Ляпуновым,
282 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ как Π А (О В С (ί). г=1 Эта запись обозначает η-кратное повторение операторов АВСУ причем символы A(i) и C(i) показывают, что спецификация этих операторов зависит от значения индекса повторения i (например, поочередное взятие величин из последовательности ячеек, образующей вектор). Для записи передач управления в зависимости от условий А. А.Ляпунов ввел понятие логических операторов, отображающих состояние памяти на два выбранных значения, скажем 0 и 1 или истина и ложь, и два парных символа, передающую ^ и приемную ) стрелки, употребляемые в программе следующим образом (Р — символ логического оператора): г г ...\...Р\... Обозначение ί (например, число) используется, чтобы выделять пары 'соответствующих друг другу приемных и передающих стрелок. При одном значении Ρ управление передается на оператор, стоящий вслед за передающей стрелкой 2, а при другом — на оператор, стоящий вслед за принимающей стрелкой * Запись программы по А. А. Ляпунову состоит из двух частей. Первая часть — схема программы — образована символами операторов и показывает порядок расположения операторов в программе, а также направления передач управления. Вторая часть — это спецификация всех операторов, образующих программу. Вот как примерно выглядела бы в этой символике программа решения 50 квадратных уравнений вида а.#2+ Ъ.х + + г. = 0 (i = 1, . . », 50, см. пример 9 в § 1.3). Схема программы: 50 12 12 Аг Л (А% (ί) Α,Α,Ρ, f A, f \A71 А8Ад (<)) Аг9 СТОП Спецификация: Аг — ввод всех коэффициентов av bv с. (i ~ 1, . . ., 50). А2 — перенос коэффициентов a., bt, с. в ячейки а, Ь, с. А3 — вычисление дискриминанта: tt ~ 2a„ t2 = 2с, дискр = Ь2 — г^· Αι — вычисление заготовок для корней: ρ = —blt^ q = ]/ \дискр\ /tlu Рь — проверка: дискр < 0? А6 — вычисление модуля и аргумента комплексной пары корней: t = ρ2 + q2, κορί = Ϋ7, κορ2 — arcsin (q/κορί). ΛΊ — вычисление пары действительных корней: κορί = ρ + #, κορ2 = ρ — g. Α8 — сохранение знака дискриминанта: призн = sign (дискр). А$ — перенос в массив решений пары корней i-ro уравнения. · А10 — печать всех решений. Оригинальная статья А. А. Ляпунова, содержащая подробное описание его символики, была опубликована в 1-м выпуске «Проблем кибернетики» (М., Физматгиз, 1958, стр. 46—74) под названием «О логических схемах программ». Научная жизнь этой методики, получившей название «операторного метода Ляпунова», началась, однако, гораздо раньше — в 1953 году, сразу после прочтения А. А. Ляпуновым курса лекций «Принципы програм-
§ 8.5. ЕЩЕ ОДИН ИСТОРИЧЕСКИЙ ОБЗОР 283 мирования» в Московском государственном университете. На основе операторного метода были созданы первые алгоритмические языки и трансляторы «доалгольного» периода 1955—1960 tf, а также разработаны первые формализмы теоретического программирования. Более подробно об этом можно прочесть в работе М. Р. Шура-Буры и автора «Становление программирования в СССР», опубликованной в 5-м номере журнала «Кибернетика» (Киев) за 1976 г. Логические схемы алгоритмов Ю. И. Янова. В 1953 г. А. А. Ляпунов взял к себе в аспирантуру молодого математика Ю. И. Янова, рекомендовав ему исследовать возможность систематических преобразований логических условий в схемах программ. Это исследование Ю. И. Яновым было блестяще выполнено, став одной из классических работ в теоретическом программировании. Ю. И. Янов рассмотрел следующую модель программ. Память программ состоит из некоторой общей памяти данных и к логических переменных р19. . ., pk. Каждый из η операторов программы Al9, . ., An действует на всю память данных и может менять некоторые из логических переменных. Логические операторы {названные им логическими условиями) имеют вид произвольной булевой функции логических переменных. Вместо стрелок f и | у А. А. Ляпунова были взяты левая \ и правая Η полускобки с тем же смыслом. В качестве значений булевых функций брались 0 (ложь) и 1 (истина). Ложное условие передает управление на правую полускобку, а истинное — на оператор, стоящий за условием. Ниже следует запись задачи о трех экспертах (§ 7.2) в виде «логической схемы алгоритма» по Ю. И. Янову: J Xl L Al (*l) -J X2 L A2 Μ J^L^3 0**3> J #1*2 V *1#2*3 V *1*2*3 L . 14 1 i 2 2 3 3 4 xtx2x3 L 0 I I _| _| Al2 (xl9 x2) xi = x2 [_ 0 [ I A13 (xu x3) xt = x3 [__ 56457 898 10 01 I A23 (x2, x3) x2 = xz | | _J xxx2 Ν/ SiSa^s V *ι*2*3 L 0 I I 11 10 7 9 11 12 13 12 A(xlt x2J x3)0\ |_J 14 6 13 Ю. И. Янов не привлекал понятия интерпретации, превращающей схему в программу, а трактовал выполнение схемы как процесс порождения множества значений схемы (последовательностей операторов) по заданной («допустимой») последовательности значений логических условий (конфигурации в нашем рассмотрении). В множество значений схемы включались не только конечные цепочки, выходящие на останов, но и значения, оканчивающиеся пустым циклом, а также бесконечные последовательности операторов. Две схемыN объявлялись равносильными (формально эквивалентными в § 7.3), если они имели совпадающие множества конфигураций. Отношение ■формальной эквивалентности, совпадающее с приведенным в этой книге (§ 7.3), было также введено Ю. И. Яновым и называлось слабой равносильностью. Для обоих видов формальной эквивалентности (т. е. равносильность и слабая равносильность) Ю. И. Яновым были описаны алгоритмы распозна» вания эквивалентности. Алгоритмы не опирались на формальные преобра* зования и не использовали в явном виде канонической формы. Для равносильности (но не слабой равносильности) Ю. И. Яновым была построена в виде исчисления полная система преобразований, состоящая из 16 схем аксиом и 4-х правил вывода. Свойство продуктивности наборов не аксиоматизировалось, поскольку это не требовалось при выбранном определении эквивалентности. Свойство достижимости также не аксиоматизировалось, и вместо аксиом верхней разметки имелось содержательно описываемое правило
284 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ «срезания» недопустимых наборов. Полное изложение результатов Ю. И. Яно- ва содержится в его работе «О логических схемах алгоритмов», также опубликованной в 1-м выпуске «Проблем кибернетики» рядом с основополагающей работой его учителя (М., Физматгиз, 1958, 75—127). Работа Дж.Ратледжа. Американский математик Дж. Ратледж внес важный вклад в развитие теории схем программ. Кстати, именно он ввел в литературу выражение «схемы (программ) Янова». Он дал независимое определение функциональной эквивалентности схем Янова и доказал равно- объемность функциональной и формальной эквивалентностей. Изложение в § 7.3 в значительной степени следует методике Дж. Ратледжа. Он рассматривает схемы Янова в абстрактной форме, не связываясь с каким бы то ни: было текстуальным или графическим представлением схемы. Вместо графа переходов он использует абстрактное отображение f \ s£xVk-*- s$> LMIE5} (^ — множество операторов и Pfe — множество наборов логических значений длины А:), которое для оператора ^е^и набора ДеР^ выдает символ оператора Aj или останова Rj или оказывается не определенным. В то же время на этом абстрактном уровне он вводит понятие канонической (матричной) формы, в которой все неэквивалентные схемы оказываются различными. В общих чертах Дж. Ратледж описывает процесс получения «всех» эквивалентных схем из канонической формы, при этом в виде прямого и обратного транзитивных замыканий он описывает процессы, аналогичные верхней и нижней разметкам. Дополнительно Дж. Ратледж делает еще одно существенное наблюдение. Назовем пару (Αι, А) -— состоянием, пару (|xj, Δ) — заключительным состоянием, пару (о, Δ) — начальным состоянием (о — символ «начала»). Длят любой схемы Янова любое состояние (А, А) (А е A (J {о)} задает конечный (может быть, пустой) набор «непосредственно достижимых» состояний {(А', А')}, где А' — единственный преемник оператора 4(4'ё^ (J {§<j})» а любой Δ' образует с Δ допустимую пару для оператора А'. Построим граф, вершинами которого будут все возможные состояния, а дуга из вершины-состояния V ведет ко всем вершинам-состояниям, непосредственно достигаемым из V. Двигаясь вдоль дуг такого графа, мы будем переходить из одного состояния в другое, а любой путь от любой начальной вершины (бесконечный, обрывающийся или выходящий на заключительное состояние) соответствует некоторой конфигурации исходной схемы. Абстрактное устройство подобного рода, могущее «переходить» из одного состояния в другое, называется конечным недетерминированным автоматом. Оказывается, что только что описанный граф, представляющий конечный автомат, полностью характеризует схему Янова. В частности, вопрос об эквивалентности схем Янова сводится к непосредственному сопоставлению характеризующих эти схемы конечных автоматов. Теория автоматов представляет собой независимо и интенсивно развивающуюся область математики, примыкающую к алгебре, теории алгоритмов и комбинаторике. Тем самым работа Дж. Ратледжа, впервые обратив внимание на связь автоматов и схем программ, пополнила «техническую базу» теоретического программирования, существенно развитую впоследствии (см., например, В. Μ. Γ л ушков, А. А. Летичевский, Теория автоматов и программирование, . 1-я Всесоюзная конференция по программированию (Пленарные доклады), Киев, 1968). Работа Дж. Ратледжа была опубликована в 1964 г. в журнале «Ассоциации по вычислительной технике» (J. Rutledge, On Ianov's program sche- mata, Journal of the Association of Computing Machinery, vol. 11, No. 1,. 1964, 1—9). Новосибирские работы. В работе А. П. Ершова «Об операторных схемах Янова», опубликованной в 20-м выпуске «Проблем кибернетики» (М., Физ-
§ 8.5. ЕЩЕ ОДИН ИСТОРИЧЕСКИЙ ОБЗОР 285- матгиз, 1968, 181—200) было введено представление схем Янова в виде графов. Это позволило упростить аксиоматику, сделав ее в то же время боле* полной, в частности, аксиоматизировав с помощью верхней разметки понятие- достижимости операторов недопустимости наборов. Изложение 8-й главы в этой книге в целом следует указанной работе. В 1968 г. Э. Л. Горель, еще будучи студенткой Новосибирского университета, исследовала аксиоматику схем Янова и доказала независимость системы аксиом, приведенной в статье А. П. Ершова. Работа следовала методологии доказательства независимости аксиом, сложившейся в математической логике (см. § 6.3), однако поиск свойств, характеризующих ту или иную аксиому, требовал немалой изобретательности, и доклад самой молодой участницы 1-й Всесоюзной конференции по программированию вызвал заслуженное одобрение специалистов (Э. Л. Горель, Логическая независимость аксиоматики операторных схем Янова. Первая всесоюзная конференция по» программированию, А. Вопросы теории программирования, Киев, 1968, 3—26).. Несколько позднее Э. Л. Горель в работе «О схемах Янова с отношением конечной эквивалентности» (Кибернетика, № 5, 1971) построила полную схему аксиом для формальной эквивалентности, при которой не допускаются конфигурации бесконечной длины, но возможны конфигурации, завершающиеся пустым циклом. Заключение. Автор включил в этот небольшой обзор только те работы, которые непосредственно привели теорию схем Янова к тому виду, в каком она излагается в этой книге. В то же время теория схем Янова в целом существенно шире, она повлияла на ряд других разделов теоретического программирования, а ее внутренняя проблематика еще далеко не исчерпана» Автор намеревается завершить этот параграф, а вместе с ним и свои беседы обсуждением одной открытой проблемы для схем Янова, за которую брались многие, но которая оказалась достаточно трудной, чтобы ее можно было бы поместить в книгу, не боясь отстать от жизни. В описанной теории все операторы в схемах Янова различны и независимы друг от друга. Вспоминая приведенную мимоходом алгебраическую формулировку, можно сказать, что в этой теории схемы Янова рассматривались над свободной полугруппой операторов. Однако еще в своей оригинальной работе Ю. И. Янов отметил важность рассмотрения схем программ, в которых существуют те или иные тождественные соотношения между операторами* и их «произведениями». Простейшим случаем соотношений являются отношения тождества вида А. = А ., т. е. когда, глядя на схему, мы можем в ней «узнавать» одинаковые операторы, входящие в разные места программы» Ю. И. Янов, а вслед за ним и Дж. Ратледжпоказали разрешимостьформаль- ной эквивалентности и ее равнообъемность с функциональной. Позднее В. Э. Иткин построил полную систему преобразований для схем с тождественными операторами. Наличие тождеств между операторами означает, что в свободную полугруппу операторов вносятся те или иные определяющие соотношения. Это» сразу вызвало к жизни попытку рассматривать схемы Янова над произвольной полугруппой операторов. При этом, однако, сразу возникли *две трудности. Важной информацией об операторах являются их сдвиги, т. е. перечень логических переменных, изменяемых операторами. Рассмотрение сколько-нибудь общих полугрупп оказалось возможным только для «пограничных» случаев — пустого или универсального распределения сдвигов. Для последнего случая А. А. Летичевский охарактеризовал некоторый класс полугрупп операторов, в которых можно гарантировать наличие алгоритма распознавания формальной эквивалентности схем. Другой подводный камень состоял в том, что найденные разрешимые случаи формальной эквивалентности оказывались некорректными, т. е. формальная эквивалентность не гарантировала функциональной эквивалентности. Это не позволяло применять результаты теории к реальным программам.
286 ГЛ. 8. ИСЧИСЛЕНИЕ РАВНОСИЛЬНЫХ ПРЕОБРАЗОВАНИЙ Особые усилия были сосредоточены на изучении схем Янова с перестановочными операторами, т. е. схемами, в которых возможны тождественные соотношения вида А В = В А. Здесь также был найден ряд разрешимых ва-1 риантов формальной эквивалентности, но в общем случае некорректной. С другой стороны, было показано, что некоторые определения эквивалентности для схем с перестановочными операторами оказываются таковыми, что для них в принципе не может существовать алгоритм.а распознавания эквивалентности. Наконец, некоторые варианты эквивалентности упираются в сравнительно давно известные, но еще не решенные проблемы общего характера, имеющие смысл и для других разделов математики. В то же время продвижение в построении содержательных теорем для схем Янова с перестановочными операторами имело бы не только важное теоретическое значение, но и помогло бы ряду прикладных проблем программирования. Более подробные ссылки и обсуждение можно найти в работе автора «Современное состояние теорем схем программ», опубликованной в 27-м выпуске «Проблем кибернетики» (М., «Наука», 1973, 87—110). Автор надеется, что найдутся читатели, которые прочтут эти строчки не просто из привычки заглядывать в конец, а прочитав эту книгу более или менее подряд. В таком случае, по-видимому, им будет понятно намерение автора не только изложить решение двух задач теоретического программирования, но и постараться продемонстрировать математический метод в действии. Читатель заметит, также некоторую несоразмерность 1-й и 2-й частей. Не исключено, однако, что изложение теории схем Янова, столь же подробное, как и схем Лаврова, сделало бы книгу слишком ватянутой и толстой. Кроме того, как было сказано во введении, 1-я и 2-я части книги преследуют разные методологические цели. Наконец, тем читателям, которые заинтересуются вопросами теоретического программирования по существу, автор рекомендует монографию В. Е. Котова «Введение в теорию схем программ», выходящую в Сибирском отделении издательства «Наука» (Новосибирск, 1978) почти одновременно с этой книгой.
УКАЗАТЕЛЬ ТЕРМИНОВ Адрес 9 Адресная часть 10 Аксиома 205 Алфавит 60 Альтернатива 147, 191 Аргумент 10, 64 Буква 60 Вершина 40, 61 — висячая 119 — достижимая 256, 258 звезда 131 — квазидостижимая 255 — Квазипродуктивная 255 — продуктивная 258 — разделяющая 132 — связанная 67 — смежная 40, 67 ι— соседняя £7 - ~ соТДОтная 133 — терминальная 119 — транзитная 80 Включение 56 Восприятие величины 80 Вход обобщенный 264 — фрагмента 263 Вывод условный 208 Выводимость 205, 214 Выработка величины 80 Выражение 13 Выход фрагмента 263 Вычисление 83 Гамак 173 Грамматика формальная 194 Граф 40 — двудольный 83 — информационный 83 — неориентированный 61 •— несовместимости 40 — п-полный 127 — ориентированный 61 — переходов 48, 64, 242 Дерево 119 — вывода 205 — равновесное 120 — разбора 195 Дизъюнкция 191 Длина (слова) 9, 60 Дополнение 59 Дуга 61 Заглушка 259 Заключение 191, 205 Замыкание транзитивное 91 обратное 101 « ограниченное 92 Импликация 191 Интерпретация 245 — формулы 204 История операционная 247 Исчисление 205 ~ корректное 206 — полное 206 Итерация 147 Квантор всеобщности 265 Код операции 10 Команда 9 Компонента 54 — связности 69 Конкатенация 146 Конфигурация 251 — остаточная 258 Конъюнкция 191 — ортогональная 27G Корень дерева 119 Краска 110 Маршрут 31, 35, 8(1 Метаязык 194 Мета переменна я 203 Минус-стрелка 230, 242 Множество 55 — занумерованное 57 — конечное 57 — пополняемое 91 — признаковое 144 — равное 56 — стартовое 91 . — счетное 57 — упорядоченное 57 — эквивалентное 56 Мощность 57 Набор 54 — допустимый 258, 266 — продуктивный 258 Независимость 206 Непротиворечивость 213 Несовместимость 39, 85, 87 Номер 57 Носитель 79 Нумерация 57 Область действия 85 — задания 58 Образ 56 — транзитивный 91 ограниченный 93 Объединение 59 — графов 67 Объект абстрактный 52 — конструктивный 59 Окрестность 1-го порядка 127 Оператор 13, 64, 242 — выполнимый 270
•288 УКАЗАТЕЛЬ ТЕРМИНОВ Оператор логический 226 — присваивания 13 — условный 13 — цикла 13 Останов 242 Отношение антирефлексивное 61 — бинарное 59 — симметричное 61 Отображение 56 — частичное 59 Отрицание 191 Оценка временная 126 — емкостная 126 — сложности 128 Память 9, 64 Перебор полный 117 Переменная величина 10, 58 — — промежуточная 10 — металингвистическая 194 — предикатная 245 Пересечение 59 — графов 67 Плюс-стрелка 230, 242 Подграф 61 Подмножество 56 Полуцикл 276 Полюс 64 Посылка 191, 205 Правило вывода 205 Предикат 226 Предшественник 61 Преемник 61 Преобразователь 242 Признак 144 Программа 9 — символическая 11 Программирование структурированное 146 Произведение прямое 59 Прообраз 56 — транзитивный 101 ограниченный 101 Процесс порождающий 252 Путь 80 Равносильность 204 — тождественная 204 г Разметка 256 — верхняя 262 — нижняя 262 — стационарная 258, 266 Разность 59 Разряд 9 Раскраска НО -j- минимальная ПО Распознаватель 242 Распределение памяти 64 каноническое 98 ■— полюсов 64 Расстояние между вершинами 132 Ребро 40, 61 Результат 10, 64 Связка 28, 35 — логическая 191 Связь информационная 22, 79 Сдвиг 242 Секвенция 214 Сечение 22 — минимаксное 120 Символ нетерминальный 195 — операторный 242 — предикатный 242 — терминальный 195 Синтаксис 194 Скелет 64 Склеивание вершин 131 Слово 60 — машинное 9 Соответствие 55 Состояние памяти 245 Стрелка входная 242 Схема аксиомы 205 — интерпретированная 245 — каноническая 270 — матричная 270 -— операторная 26, 65 — равная 270 — сравнимая 246, 247 — формулы 203 — эквивалентная 247 — Янова 237, 242 Таблица истинности 191 Терминал 119 Тождество 191 Условие 242 — полное 266 Устройство исполнительное 9 Форма совершенная нормальная 199 Формула логическая 192 ι— металингвистическая 194 — общезначимая 211 — эквивалентная 204 Фрагмент 263 — обобщенный 264 Функция 59 — булева 197 ■— выборки 54 — частичная 59 Цепочка 276 — правильная 276 Цикл 276 Число хроматическое ПО Ширина 24 Шкала логическая 144 Эквивалентность 247 — операционная 248 — формальная 252 ·— функциональная 247 Язык 194 ·— алгоритмический 12 ·— машинный 11 Ячейка 9
А. П. Ершов ВВЕДЕНИЕ В ТЕОРЕТИЧЕСКОЕ ПРОГРАММИРОВАНИЕ