Что изучает математическая логика и зачем она нужна программисту

Роль логического программирования, и стоит ли планировать его изучение на 2021-й

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

Итак, пришло время второй ссылки. Что это будет? Статья на Хабре? Может быть статья на ином ресурсе? Прочитав пару первых абзацев на разных сайтах, вы, скорее всего, мало что поймете, так как, во-первых, материал обычно ориентирован на знающего читателя, во-вторых, хорошей и понятной информации по теме не так много в русскоязычном интернете, в-третьих, там почему-то постоянно речь идёт о некоем «прологе» (речь о языке программирования Prolog, разумеется), но сам язык, кажется, использует мало кто (почётное 35 место в рейтинге TIOBE). Однако наш герой не теряет мотивации и, спустя некоторое время, натыкается на эту самую статью, желая, все-таки понять:

Что такое логическое программирование

Какова история его создания и фундаментальные основы (серьезно, какому новичку это может быть интересно?)

Зачем и где его применяют

Стоит ли лично вам его изучать

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

Что изучает математическая логика и зачем она нужна программисту. Смотреть фото Что изучает математическая логика и зачем она нужна программисту. Смотреть картинку Что изучает математическая логика и зачем она нужна программисту. Картинка про Что изучает математическая логика и зачем она нужна программисту. Фото Что изучает математическая логика и зачем она нужна программисту

Что такое логическое программирование

В школе на уроках информатики многие, если не все, слышали про Pascal (а кто-то даже писал на нем). Многие также могли слышать про Python, C/C++/C#, Java. Обычно программирование начинают изучать именно с языков из этого набора, поэтому все привыкли, что программа выглядит как-то так:

Этот яркий, но малоинформативный пример призван показать, что обычно команды выполняются одна за другой, причем мы ожидаем, что следующие инструкции (команды) могут использовать результат работы предыдущих. Также мы можем описывать собственные команды, код которых будет написан подобным образом. Остановимся на том, что как завещал Фон Нейман, так компьютер и работает. Машина глупа, она делает то, что скажет программист, по четкому алгоритму, последовательно выполняя инструкции. Не может же, в конце концов, компьютер, подобно мыслящему живому существу, делать выводы, строить ассоциативные ряды… Или может?

Давайте устроимся поудобнее рядом со своим компьютером и порассуждаем о жизни и смерти вместе с Аристотелем:

Следовательно, Сократ смертен.

Звучит логично. Но есть ли способ научить компьютер делать выводы как Аристотель? Конечно! И вот тут мы вспомним о Prolog-e, который так часто мелькает при поиске информации о логическом программировании. Как несложно догадаться, Prolog (Пролог) является самым популярным чисто логическим языком программирования. Давайте рассуждения об этом языке оставим на следующие разделы статьи, а пока что продемонстрируем «фишки» логических языков, используя Пролог.

Напишем небольшую программу, где перечислим, кто является людьми (ограничимся тремя) и добавим правило «всякий человек смертен»:

Что ж, давайте спросим у компьютера, смертен ли Сократ:

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

Что изучает математическая логика и зачем она нужна программисту. Смотреть фото Что изучает математическая логика и зачем она нужна программисту. Смотреть картинку Что изучает математическая логика и зачем она нужна программисту. Картинка про Что изучает математическая логика и зачем она нужна программисту. Фото Что изучает математическая логика и зачем она нужна программисту

Предикат a от трех аргументов вернет истину, если удастся доказать истинность предикатов b, c и d. Читаются правила справа налево следующим образом: «Если b от X истинно И c от Y, Z истинно И d истинно, то a от X, Y, Z истинно».

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

Теперь начнём делать запросы к программе (всё те же предикаты):

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

Какие задачи и как можно решать с помощью логического программирования

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

Пусть производная получилась довольно громоздкой, но мы и не ставили цель её упростить. Главное, из примера видно, что правила вывода производной на Prolog-е описываются очень близким образом к их математическому представлению. Чтобы сделать подобное на привычных языках программирования, пришлось бы вводить понятие дерева выражений, описывать каждое правило в виде функции и т. д. Тут же мы обошлись 8-ю строками. Но здесь важно остановиться и задуматься: компьютер не начал работать как-то иначе, он все ещё обрабатывает последовательности команд. Стало быть, те самые деревья, которые где-то все-таки должны быть зашиты, чтобы программа работала, действительно присутствуют, но в неявном виде. Деревья эти именуют «деревьями вывода», именно они позволяют подбирать нужные значения переменных, перебирая все возможные варианты их значений (существует механизм отсечения, который является надстройкой над логической основой языка, но не будем об этом).

Давайте на простом примере рассмотрим, что из себя представляет перебор, а затем то, чем он может быть опасен.

Ага…то есть Петя, Петя и ложь… Что-то не так, подумает программист и попробует разобраться. На самом деле, перебирая все варианты значений X, Пролог пройдёт по такому дереву:

Что изучает математическая логика и зачем она нужна программисту. Смотреть фото Что изучает математическая логика и зачем она нужна программисту. Смотреть картинку Что изучает математическая логика и зачем она нужна программисту. Картинка про Что изучает математическая логика и зачем она нужна программисту. Фото Что изучает математическая логика и зачем она нужна программисту

Что изучает математическая логика и зачем она нужна программисту. Смотреть фото Что изучает математическая логика и зачем она нужна программисту. Смотреть картинку Что изучает математическая логика и зачем она нужна программисту. Картинка про Что изучает математическая логика и зачем она нужна программисту. Фото Что изучает математическая логика и зачем она нужна программисту

Представим, что перед нами в ячейках расположены три чёрных и три белых шара (как на картинке выше), которые требуется поменять местами. За один ход шар может или передвинуться в соседнюю пустую клетку, или в пустую клетку за соседним шаром («перепрыгнуть» его). Решать будем поиском в ширину в пространстве состояний (состоянием будем считать расположение шаров в ячейках). Суть этого метода заключается в том, что мы ищем все пути длины 1, затем все их продления, затем продления продлений и т. д., пока не найдем целевую вершину (состояние). Почему поиск в ширину? Он первым делом выведет самый оптимальный путь, то есть самый короткий. Как может выглядеть код решения:

Со стороны улучшения алгоритма можно предложить использовать поиск в глубину. Но как же, он ведь не даст оптимального результата? Сделаем просто: ограничим глубину поиска. Так мы точно не забьём стек и, возможно, получим ответ. Поступим так: проверим, есть ли пути длины 1, затем длины 2, затем длины 4 и т. д. Получим так называемый поиск с итерационным заглублением:

Во-первых, здесь стоит обратить внимание, что мы не используем очереди, а также внешних предикатов (кроме reverse, но он для красоты). Это потому, что поиск в глубину естественен для Пролога (ищите картинку с деревом выше). Во-вторых, пусть мы и делаем вроде как «лишние» действия, то есть для каждого нового значения глубины проходим по всем путям заново, мы практически не теряем в скорости относительно поиска в ширину (может в несколько раз, но не на порядок), при этом значительно экономим память. В-третьих, мы наконец-то получаем ответ, и это самое главное. Приводить его не буду, так как он займет много места, но для интриги оставлю вам его длину: 16.

С другой стороны, задачу можно было бы решить, не меняя код поиска, а лишь изменив правила перемещения шаров. Обратим внимание, что нам заранее известны входные и выходные данные. Приглядевшись становится понятно, что нет никакого смысла в движении фишек «назад». Действительно, если чёрным нужно встать в правые позиции, то какой смысл делать ходы влево? Перепишем предикаты движения:

Хм, код стал даже проще. Запустив мы убедимся, что поиск (оба варианта), во-первых, работает, во-вторых, работает быстро, в-третьих, работает быстро и выводит результат. Это успех. Мало того, что мы решили задачку, только что был создан самый настоящий искусственный интеллект. Программа получает входные данные и желаемый результат, а затем сама ищет, как его достигнуть. Да, это однозначно успех.

Что изучает математическая логика и зачем она нужна программисту. Смотреть фото Что изучает математическая логика и зачем она нужна программисту. Смотреть картинку Что изучает математическая логика и зачем она нужна программисту. Картинка про Что изучает математическая логика и зачем она нужна программисту. Фото Что изучает математическая логика и зачем она нужна программисту

Зачем и где применяют логическое программирование

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

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

Стоит ли планировать его изучение на 2021-й

Тут оставлю своё субъективное мнение, разделённое на две части:

И здесь остаётся лишь пожелать продуктивного 2021-го года!

Хочется выразить особую благодарность Дмитрию Сошникову за знакомство с этой удивительной парадигмой.

Источник

Математическая логика и логическое программирование

Возникновение языка ПРОЛОГ и его развитие

После того как Робинсон в 1965 г. открыл правило вывода, названное им правилом резолюции, значительно активизировались работы по созданию автоматизированного метода доказательства теорем через опровержение. Первоначально попытки создания алгоритма решения задач, базирующегося на правиле резолюции, оказывались успешными только для очень небольших задач. Существенно усовершенствовали такие алгоритмы Лавленд, Ковальски и Куэнер, разработав метод устранения моделей (1968) и метод селектирующей функции (1971). В 1974 г. Ковальски первым предложил метод, в соответствии с которым логический язык (именно язык логики предикатов) можно было бы использовать как язык программирования. Кольмерор и Руссель воспользовались результатами этих работ и к 1975 г. создали язык программирования, основывающийся на логике предикатов и правиле резолюции, названный ими ПРОЛОГ.

В течение 1970-х гг. язык ПРОЛОГ прошел путь развития от интересующего лишь узких специалистов экспериментального языка, созданного европейскими учеными, до одного из ведущих языков программирования, широко используемого во всем мире. В 1977 г. Уоррен и Перейра из Эдинбургского университета (Великобритания) создали интерпретатор/компилятор языка ПРОЛОГ для компьютера DEC-10, а в 1980 г. в Империэл Колледже разработан интерпретатор языка микроПРОЛОГ для персональных компьютеров.

В 1981 г. в Японии было объявлено о начале работ по созданию компьютеров пятого поколения. Они должны отличаться от компьютеров предыдущих поколений тем, что в них встроены функции программиста. По словесному заданию задачи, сформулированному на ограниченном профессиональном языке, эти компьютеры способны сами построить необходимую рабочую программу (синтезировать ее из отдельных модулей, хранящихся в памяти компьютера) и выполнить ее. В качестве основной методологии разработки программных средств для компьютеров пятого поколения было избрано логическое программирование. В состав такого компьютера должна входить так называемая база знаний, в которой хранится информация о закономерностях, присущих’ данной проблемной области, и методах решения характерных для нее задач. Кроме того, в его состав должен входить специальный блок — решатель, который осуществляет процедуры логического вывода. С помощью решателя на основании сведений из базы знаний автоматически синтезируются нужные для пользователя программы. Полезный эффект от таких систем будет заключаться в том, что в распоряжение широких слоев общества будут предоставлены мощные вычислительные ресурсы и что возрастет производительность труда в ряде отраслей промышленности, в которых сейчас она традиционно низка.

Общая характеристика языка ПРОЛОГ

Язык ПРОЛОГ существенно отличается от традиционных алгоритмических языков программирования, таких, как «Бейсик», «Паскаль» и т.п. При использовании последних для решения задач на компьютере пользователь сначала должен разработать алгоритм решения задачи, затем записать (закодировать) его на алгоритмическом языке программирования и, наконец, «прогнать» программу на компьютере и получить результат.

В ПРОЛОГЕ дело обстоит иначе. Пользователь лишь формулирует задачу, осуществляет ее постановку, т.е. сообщает компьютеру необходимые факты и правила, по которым эти факты соотносятся друг с другом. Затем формулируется вопрос, на который компьютер отвечает самостоятельно, исходя из той «базы знаний», т.е. набора фактов и правил, которые пользователь сообщил компьютеру. Запись фактов происходит на языке логики предикатов. Правило построения выводов из имеющихся фактов — правило резолюции. Таким образом, ПРОЛОГ — это язык описания фактов, правил вывода заключений и постановки вопросов к базам данных, записываемых на языке математической логики. Фактически вопрос представляет собой теорему логики предикатов, а работа программы состоит в том, чтобы доказать эту теорему на основе фактов и правил из базы данных.

Компьютерная система языка ПРОЛОГ представляет собой интерпретатор, состоящий из следующих независимых подпрограмм: сканер, унификатор, управление, печать.

Подпрограмма сканер осуществляет синтаксический контроль исходного текста программы и его перевод во внутреннюю форму хранения программы — в дерево. Дерево хранится в памяти машины в виде упорядоченной совокупности массивов.

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

Подпрограмма управления осуществляет процесс поиска доказательства. Алгоритм ее действия основан на правиле резолюции. Чтобы этот процесс произошел, программист должен четко описать задачу при помощи так называемых фраз (или клауз, или формул, или дизъюнктов) Хорна, выраженных на языке ПРОЛОГ. В каждой фразе формулируется некоторое отношение между термами. Терм — это обозначение, представляющее некоторую сущность из исследуемой области. Для того чтобы привести в действие данный алгоритм решения задачи, программист должен написать вопрос, согласно которому будет необходимо выяснить, является ли конкретная формула следствием заданного множества формул, представленных в программе.

Наконец, подпрограмма печать выводит на экран все значения переменных, указанных в вопросе и удовлетворяющих совокупности фактов и правил.

Краткое описание языка ПРОЛОГ и примеры

Язык ПРОЛОГ начинается со следующих основных синтаксических конструкций.

Выделяют следующие три типа таких предложений: факт, правило и вопрос.

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

Пример 40.1. В качестве примера рассмотрим задачу из курса химии 7-го класса: какие химические элементы могут вступать в реакцию друг с другом.

Прежде всего создадим «базу знаний» для данной задачи. (Обратим внимание на то, что в конце каждого терма необходимо ставить знак «;», а в правилах вместо союза «и» ставить запятую.) База знаний данной задачи имеет вид:

Вопросы к базе знаний в ПРОЛОГЕ выражаются в форме предикатов, перед которыми ставится знак «?» При этом искомые значения обозначаются переменными:

Задачу можно усложнить, добавив в базу знаний в качестве фактов все элементы таблицы Менделеева, а в качестве правил — все возможные реакции взаимодействия между ними.

Пример 40.2. Рассмотрим еще один пример ПРОЛОГ-программы. Составим программу классификации животных. Это — одна из ведущих тем в курсе биологии 7-го класса. Прежде всего необходимо установить существенные определяющие признаки для такой системы классификации животных. Введем предикат, фиксирующий эти признаки животного:

Теперь можем задавать вопросы. На вопрос «? РЫБА(x);» получим ответ x = окунь; на вопрос «? МЛЕКОПИТАЮЩЕЕ(x);» получим ответ x = волк и т. д.

Имеющуюся базу знаний можно расширять, вводя в нее новые факты и новые правила. Например, предикат поведения:

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

Сферы применения языка ПРОЛОГ

Во-первых, на языке ПРОЛОГ прекрасно реализуется модель реляционной базы данных, представляющая собой хорошо разработанный формализм.

Во-вторых, исследователи, специализирующиеся в области программной инженерии, показали, что логическую спецификацию системы можно непосредственно преобразовать в логическую программу на языке ПРОЛОГ.

В-третьих, Кольмеррор, создавший язык ПРОЛОГ, первоначально предназначал его для обработки естественного языка. Он разработал на ПРОЛОГЕ систему грамматического разбора естественного языка нисходящим методом. Этот формализм был доработан учеными, которые продемонстрировали его успешное применение к системам, которые обрабатывают запросы, сформулированные на естественном языке.

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

В-пятых, при представлении знаний одной из главных задач является выбор такой формы представления, которая может быть использована в экспертных системах. При помощи ПРОЛОГА были построены экспертные системы для ряда сфер, включая решение уравнений, медицину, законодательство, юриспруденцию, архитектуру, автоматизацию заводского производства, проектирование электронных схем, синтез микропрограмм, анализ финансового положения и помощь в принятии решений. Простейшие примеры экспертных систем были рассмотрены в предыдущем пункте.

Источник

Математическая логика и языки программирования

Образно выражаясь, можно сказать, что компьютер состоит из материальной части и математического (программного) обеспечения, или, используя профессиональную лексику, из «железа» и «обуви». И к тому, и к другому имеет самое непосредственное отношение математическая логика, ни первое, ни второе без математической логики обойтись не могут. Ранее здесь и здесь было рассмотрено применение математической логики к релейно-контактным (переключательным) схемам, являющимся неотъемлемой составной частью современного компьютера. Часть настоящей главы также посвящена вопросам взаимодействия математической логики и компьютеров. Так, в этой статье рассказывается о применении математической логики к языкам программирования и к самому процессу программирования и получающимся в результате этого программам. В статье дается характеристика обратного процесса — применению компьютеров для поиска доказательств теорем математической логики и других математических дисциплин. Значительное внимание уделено методу резолюций для доказательства теорем в исчислениях высказываний и предикатов. В статье кратко описывается язык ПРОЛОГ — принципиально новый язык программирования, выросший непосредственно из математической логики (логики- предикатов) и призванный стать языком компьютеров пятого поколения.

В свою очередь, информатика как наука начала оформляться вместе с созданием и бурным развитием вычислительной техники. Ее формирование и определение ее предмета продолжаются по настоящее время. Информатика — наука о хранении, обработке и передаче информации с помощью компьютеров. Она включает в себя крупные разделы, изучающие алгоритмические, программные и технические средства хранения, обработки и передачи информации. Математическая логика оказалась единственной математической наукой, методы которой стали мощнейшими инструментами познания во всех разделах информатики. Поэтому сколько-нибудь серьезное изучение информатики немыслимо без освоения основ математической логики.

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

Чтобы компьютер работал, он должен быть оснащен программным обеспечением, т.е. комплексом программ, ориентирующих компьютер на решение задач того или иного класса. (Слово «программа» имеет греческое происхождение и означает «объявление», «распоряжение».) Уже само понятие компьютерной программы, предусматривающее четкое алгоритмическое предписание компьютеру о порядке и характере действий, предусматривает проникновение в программу, а также в процесс ее составления (в программирование) теории алгоритмов. Но при более пристальном рассмотрении процесс проникновения логики в программы и программирование оказывается значительно более глубоким и органичным. Не только один ее раздел — теория алгоритмов — работает здесь, но исключительно действенным оказывается само существо математической логики — ее язык, ее аксиоматические теории, выводы и теоремы в них, свойства этих теорий.

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

Теория алгоритмов и математическая логика — фундаментальная основа программирования. В 30-е гг. XIX в. английский математик Чарлз Бэббедж высказал впервые идею вычислительной машины. И только сто лет спустя логики разработали четыре математически эквивалентные модели понятия алгоритма (мы достаточно подробно рассмотрели в предыдущей главе три из них). Именно в теории алгоритмов были предугаданы основные концепции, которые легли в основу принципов построения и функционирования вычислительной машины с программным управлением и принципов создания языков программирования. Идею такой вычислительной машины впервые смогли реализовать болгарский ученый С. Атанасов в 1940 г. и немецкий ученый К. Цузе в 1942 г. Четыре главные модели алгоритма породили разные направления в программировании.

Первая модель — это абстрактная вычислительная машина (А. Тьюринг, Р. Пост). Она явилась абстрактным прообразом реальных вычислительных машин. До сих пор все вычислительные машины в некотором смысле базируются на идее Тьюринга: их память физически состоит из битов, каждый из которых содержит либо 0, либо 1. Программное управление унаследовало от этих абстрактных машин и программу, помещенную в «постоянную память» (идея поместить программу ЭВМ в основную память, чтобы иметь возможность изменять ее в ходе вычислений, принадлежит Джону фон Нейману), а структура команды современной ЭВМ в значительной степени напоминает структуру команды машины Тьюринга. В рамках теории машин Тьюринга откристаллизовались важнейшие для компьютерных приложений логики понятия: вычислимая функция, разрешимая задача, неразрешимая (алгоритмически) задача. Собрано большое количество определений абстрактных вычислительных машин и показано, как каждое из них можно свести к другому подходящей кодировкой входов и выходов.

Другая модель — это рекурсивные функции, идея которых восходит к гильбертовскому аксиоматическому подходу. От них унаследовало свои основные конструкции современное структурное программирование.

Третий способ описания алгоритмов — нормальные алгоритмы А. А. Маркова. Они послужили основой языка Рефал и многих других языков обработки символьной информации.

Четвертое направление в теории алгоритмов — так называемое λ-исчисление — базируется на идеях советского логика Р.Шейнфинкеля и американского логика X. Б. Карри. Оказалось, что для определения всех вычислимых функций достаточно операций так называемой λ-абстракции и суперпозиции. Идеи λ-исчисления активно развиваются в языке Лисп, функциональном программировании и во многих других перспективных направлениях современного программирования.

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

Описание компьютерных программ с помощью математической логики

Первые попытки применить в программировании развитые логические исчисления и методы формализации предпринял американский логик X. Б. Карри. В 1952 г. он сделал доклад «Логика программных композиций», идеи которого опередили свое время по крайней мере на четверть века. Карри рассмотрел задачу программирования как задачу составления более крупных программ из готовых кусков. Были введены две базисные системы конструкций: первая — последовательное исполнение, разветвление и цикл, вторая — последовательное исполнение и условный переход. Он охарактеризовал логические средства, какие можно использовать для композиции программ из подпрограмм в каждом из этих случаев.

Как известно, компьютер является своего рода «идеальным бюрократом»: он не воспримет программу, написанную на не до конца формализованном языке, и приступит к работе лишь после того, как все выражено в полном соответствии с детальными инструкциями. Поэтому в 1960-е гг. на первый план вышли задачи точного определения формальных языков достаточно сложной структуры. Математическая логика, подпитываемая идеями программирования, успешно с ними справилась, разработав описание синтаксиса сложных и богатых по выразительным средствам формальных языков.

В середине 1960-х гг. практически одновременно появился ряд пионерских работ в области описания условий, которым удовлетворяет программа. Советский математик В. М. Глушков в 1965 г. ввел понятие алгоритмической алгебры, послужившее прообразом алгоритмических логик. Ф. Энгелер в 1967 г. предложил использовать языки с бесконечно длинными формулами, чтобы выразить бесконечное множество возможностей, возникающих при разных исполнениях программы. Но наибольшую популярность приобрели языки алгоритмических логик. Эти языки были изобретены практически одновременно американскими логиками Р.У.Флойдом (1967), С.А.Р.Хоаром (1969) и учеными польской логической школы, например А. Сальвицким и др. (1970).

Наряду с динамической логикой 1-го порядка рассматривается пропозициональная динамическая логика и ее обобщение — так называемая логика процессов, в которой выразимы некоторые свойства программы, зависящие от процесса ее выполнения. Различные динамические логики получаются при варьировании средств языков программирования, используемых в программах. Эти средства содержат массивы и другие структуры данных, рекурсивные процедуры, циклические конструкции, а также средства задания недетерминированных программ.

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

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

Принципиально иной способ определения семантики программ, пригодный, скорее для описания всего алгоритмического языка, а не конкретных программ, предложил в 1970 г. американский логик Д. Скотт. Он построил математическую модель λ-исчисления и показал, как переводить функциональное описание языка структурного программирования в λ-исчисление и как определить математическую модель алгоритмического языка через модель λ-исчисления. Эта так называемая денотационная семантика алгоритмических языков, работы по которой насчитываются уже тысячами, стала практическим инструментом построения надежных трансляторов со сложных алгоритмических языков. Так еще одна абстрактная область математической логики нашла прямые практические приложения.

Описание программирования и анализ его концепций с помощью математической логики

Программирование — это процесс составления программы, плана действий. Было замечено, что классическая логика плохо подходит для описания этого процесса хотя бы потому, что она плохо подходит вообще для описания всякого процесса в математике. Еще в начале XX в. стало ясно, что в математике Давно разошлись понятия «существовать» и «быть построенным», с античных времен трактовавшиеся как синонимы. Были выявлены так называемые математические объекты-«привидения» (множества, Функции, числа), существование которых доказано, но построить которые нельзя. Причиной их появления явился эффект сочетания классической логики с теоремой Гёделя о неполноте формальной арифметики. Один из фундаментальных законов классической логики — закон исключенного третьего в некоторой свободной трактовке фактически означает, что мы знаем все. Этот постулат конечно же никак нельзя назвать реалистическим: мы знаем чрезвычайно мало, и чем больше узнаем, тем лучше это понимаем. Голландский математик Л. Э. Я. Брауэр определил логические корни «привидений» еще до открытия теоремы Гёделя, в 1908 г., и начал построение так называемой интуиционистской математики, не принимающей закон как универсальный. В 1930–1932 гг. другой голландец А. Гейтинг строго сформулировал логику, которой пользовались в интуиционистской математике, — интуиционистскую логику. Ее математическая интерпретация, данная советским математиком А. Н. Колмогоровым в то же время, сохранила свое значение до сих пор.

Описание программирования с помощью логики основано на определенной аналогии между выводом формулы в некотором логическом исчислении и программой решения задачи, отвечающей этой формуле при конструктивной интерпретации логики. Логическая теория, соответствующая структурным схемам программ, появилась в середине 1980-х гг. Структурные схемы соответствовали нарождающемуся новому типу логики — логики схем программ, которой пользуется программист для создания сложных, многовариантных, итеративных планов действий.

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

правило условного оператора (ПУО);

правило релаксации (ПР);

правило зацикливания (ПЗ);

правило бесконечного цикла (ПБЦ);

Таким образом, конструктивное описание ситуации, где классические средства работают плохо, оказалось весьма компактным и эффективным.

Логика — лишь одна из простейших логик схем программ, успешно используемых в автоматизированном планировании действий.

Задача построения программы выражается в интуиционистской логике с помощью функциональной формулы:

Здесь — входные переменные создаваемой программы; — ее результаты; задают связи вход-выход; амбивалентны: они могут представлять как условия на входы, так и входные значения сложных типов (структуры данных, функции-параметры). Например, формула

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

Но повышение выразительной силы и «аккуратности» выводов в интуиционистской логике по сравнению с классической имеет и оборотную сторону: поиск вывода в ней существенно сложнее. В частности, метод резолюций в ней неприменим, потому что формулы не могут быть разложены на дизъюнкты.

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

Впервые на возможности логики в качестве инструмента анализа понятий программирования обратили внимание в середине 1970-х гг. в связи с развитием теории верификации (проверки правильности) программ. Оказалось, что для многих конструкций программирования, совместное использование которых не приводит к алгоритмической невычислимости, невозможно построить полную формальную систему, описывающую их взаимодействие. Например, рассмотрение логики схем программ позволило установить, что операторы GOTO естественно получаются в том случае, если все рассматриваемые действия можно считать глобальными преобразованиями состояния системы. Циклы оказались хорошо совместимы с массивами и плохо — с рекурсивными структурами данных, а процедуры высших типов — наоборот. Массивы и сложные структуры данных плохо совместимы с присваиваниями (в данном случае присваивание дается на целый ряд операторов, несущих различный логический смысл).

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

Верификация (доказательство правильности) программ с помощью математической логики

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

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

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

Говорить о правильности программы самой по себе бессмысленно. Программа пишется с целью решения той или иной конкретной задачи. Каждая правильно поставленная задача содержит в себе условие (то, что дано) и вопрос, на который нужно дать ответ. При составлении программы условие задачи превращается в предусловие, а вопрос преобразуется в постусловие, имеющее уже форму не вопроса, а утверждения, которое должно быть истинно всякий раз, когда ответ на вопрос задачи правилен.

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

Для доказательства частичной правильности операторных программ обычно используются различные модификации метода Флойда, который состоит в следующем. На схеме программы выбираются контрольные точки так, чтобы любой циклический путь проходил по крайней мере через одну точку. С каждой контрольной точкой ассоциируется специальное условие (индуктивное утверждение или инвариант цикла), которое истинно при каждом переходе через эту точку. С входом и выходом схемы также ассоциируются пред- и постусловия. Затем каждому пути программы между двумя соседними контрольными точками сопоставляется так называемое условие правильности. Выполнимость всех условий правильности гарантирует частичную правильность программы.

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

Одна из модификаций метода Флойда заключается в построении конечной аксиоматической системы (так называемой «логики Хоара»), состоящей из схем аксиом и правил вывода, в которой в качестве теорем выводимы утверждения о частичной правильности программ, в частности на языке программирования Паскаль. Такая система используется и для задания аксиоматической семантики языка Паскаль. Аксиоматические системы, родственные логике Хоара, разработаны и для других алгоритмических языков программирования.

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

б) после завершения цикла;

в) в ходе выполнения цикла.

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *