TURBO PASCAL

Новости

Программы   

Turbo Pascal 

Игры

Документация   

Странности

FAQ

Ссылки

Форум

Живой Журнал

Гостевая книга

Рассылка

Благодарности

Об авторе

О абстракции исполнения 

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

Чтобы разъяснить, что подразумевается под "вычислением", я опишу сейчас невычислительную конструкцию "получения" (я преднамеренно не употребляю термина "вычисление"), например, наибольшего общего делителя чисел 111 и 259. Она состоит из двух картонных карточек, расположенных одна поверх другой. На верхней карточке написан текст "НОД(111,259) =". Чтобы получить от конструкции ответ, мы поднимаем верхнюю карточку и кладем ее слева от нижней, на которой теперь можно прочесть текст "37".

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

Чтобы преодолеть меньшее затруднение, мы могли бы рассмотреть изображение на огромном листе картона большого прямоугольного массива из сетевых точек с целыми координатами хну, удовлетворяющими отношениям 0 < х < 500 и 0 < у < 500. Для каждой такой точки (х,у) с положительными координатами (т. е. за исключением точек на осях) мы можем выписать в соответствующей позиции значение НОД(ж,у); предлагается двумерная таблица из 250000 элементов. С точки зрения полезности это значительное усовершенствование: вместо конструкции, способной выдавать наибольший общий делитель единичной пары чисел, мы имеем теперь "конструкцию", способную выдавать наибольший общий делитель любой пары из 250000 различных пар чисел. Это много, но особенно радоваться нечему, так как указанный ранее второй недостаток (почему мы должны верить, что конструкция выдает правильный ответ?) помножился на те же самые 250 000, и теперь от нас требуется уже совсем безграничное доверие к ее изготовителю. Поэтому перейдем к рассмотрению другой конструкции. На таком же листе картона с сетевыми точками написаны только числа, пробегающие значения от 1 до 500 вдоль обеих осей. Кроме того, начерчены следующие прямые линии:

1) вертикальные линии (с уравнением х = константа);

2) горизонтальные линии (с уравнением у = константа);

3) диагонали (с уравнением х + у = константа);

4) "линия ответа" с уравнением х = у.

Чтобы работать на этой машине, мы должны следовать следующим инструкциям ("играть по следующим правилам"). Когда хотим найти наибольший общий делитель двух чисел X и Y, мы помещаем фишку — также поставляемую изготовителем — в сетевую точку с координатами х = X и у = Y. Коль скоро фишка не находится на "линии ответа", рассматриваем наименьший равнобедренный прямоугольный треугольник, у которого вершина прямого угла совпадает с фишкой, а один из концов гипотенузы (либо низке фишки, либо слева от нее) находится на одной из осей. (Поскольку фишка не лежит на линии ответа, такой прямоугольный треугольник будет иметь на осях только одну вершину.) Затем фишка перемещается в сетевую точку, совпадающую с другим концом гипотенузы. Такое перемещение повторяется до тех пор, пока фишка не достигнет линии ответа. После этого ж-координата (или у-координата) окончательного положения фишки является искомым ответом.

Как нам убедиться в том, что эта машина будет выдавать правильный результат? Если (х,у) — любая из 249 500 точек не на линии ответа и (х'у') — точка, в которую передвинется фишка за один шаг игры, то либо ж' = хну' = у —ж, либо ж' = х — уиу' = у. Нетрудно доказать, что НОД(ж, у) = НОД(ж', у'). Важный момент здесь состоит в том, что одно и то же рассуждение применяется одинаково верно к любому из возможных шагов! Кроме того, — и опять-таки без труда — мы можем доказать для любой точки (ж, у) где ж = у (т.е. (ж, у) является одной из 500 точек на линии ответа), что НОД(ж, у) = х. И снова важный момент в том, что одинаковое рассуждение применимо к любой из 500 точек на линии ответа. В-третьих,— и вновь это не составит труда — нам нужно показать, что при любом исходном положении (X, Y) конечное число шагов в самом деле перенесет фишку на линию ответа, и опять важно отметить, что одно и то же рассуждение одинаково применимо к любому из 250 000 исходных положений (X, Y). Три простых рассуждения, пространность которых не зависит от числа сетевых то-

чек: эта миниатюра показывает, насколько велики возможности математики. Если обозначить через (ж, у) произвольное положение фишки на протяжении игры, начатой в положении (X, У), то первая наша теорема позволяет утверждать, что во время этой игры отношение НОД(ж, у) = НОД(^Г, Y) будет всегда справедливо, или — выражаясь на соответствущем жаргоне — "оно сохраняет инвариантность". Далее, вторая торема гласит, что мы можем интерпретировать ж-координату окончательного положения фишки как требуемый ответ, а третья теорема гласит, что такое окончательное положение существует (т. е. будет достигнуто за конечное число шагов) И этим завершается анализ того, что мы могли бы назвать "нашей абстрактной машиной".

Теперь нам остается убедиться в том, что лист, поступивший от изготовителя, является на самом деле правильной моделью абстрактной машины. Для этого нужно проверить нумерацию вдоль обеих осей, а также проверить, правильно ли проведены все прямые линии. Это несколько затруднительно, так как предстоит исследовать объекты, число которых пропорционально N, где N (в нашем примере 500) — длина стороны квадрата, но все же предпочтительнее, чем N2, число возможных вариантов вычисления.

Другая машина могла бы работать не с огромным листом картона, а с двумя девятибитовыми регистрами, в каждом из которых можно запомнить двоичное число от 0 до 500. При этом мы могли бы использовать один регистр для запоминания значения ж-координаты, а другой — для запоминания значения у-координаты, соответствующей "текущему положению фишки". Перемещение тогда соответствует уменьшению содержимого одного регистра на содержимое другого. Мы могли бы реализовать арифметику самостоятельно, но, разумеется, лучше, если машина сможет делать это за нас. Если мы захотим полагаться на полученный ответ, то нам нужно уметь убеждаться в том, что машина правильно выполняет операции сравнения и вычитания. В уменьшенном масштабе повторяется та же история: мы выводим единожды и на все случаи, т.е для любой пары п-разрядных двоичных чисел, уравнения для устройства двоичного вычитания, а затем удостоверяемся в том, что наша физическая машина правильно моделирует это абстрактное устройство. Если это устройство параллельного вычитания, то число проверок — пропорциональное числу элементов и их взаимосвязей — пропорционально значению п = Iog2 N. В последовательной машине сделан еще один шаг на пути упрощения оборудования за счет расхода времени.

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

Вместо того чтобы рассматривать одиночную проблему вычисления НОД(111,259), мы обобщили ее и подошли как к частному случаю более широкого класса проблем вычисления НОД(^Г, Y), Стоит отметить, что мы могли бы обобщить проблему вычисления НОД(111,259) по-разному: можно было бы рассматривать эту задачу как частный случай иного, более широкого класса задач, например вычисления НОД(111,259), НОК(111,259), 111 х 259, 111 + 259, 111/259, 111 - 259, 111259, дня недели для 111-го дня 259-го года нашей эры и т. д. В результате мог бы появиться "процессор для 111 и 259", и для того, чтобы он выдал упомянутый выше ответ, нам следовало бы дать на его вход команду "ПОД, пожалуйста". Вместо этого мы предложили "НОД-вычислитель", которому для получения этого ответа потребуется задать на вход пару чисел "111, 259" и это совсем другая машина!

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

1. Мы должны иметь полную ясность относительно способа обобщения, т. е. должны тщательно выбрать и явно определить более широкий класс, поскольку наши рассуждения должны применяться ко всему этому классу.

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

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

НОД-вычислитель был бы столь же плох, если бы он представлял собой таблицу из 250000 записей, содержащих "заготовленные" ответы. Его характерное отличие в том, что он может быть задан в форме компактного набора "правил игры", который, если играть в соответствии с этими правилами, обеспечит выдачу нужного ответа.

Огромный выигрыш состоит в том, что единое рассузкдение применительно к этим правилам позволяет нам доказывать существенные утверждения о результатах любого варианта игры. Это достигается ценой того, что при каждом из 250 000 конкретных применений этих правил мы получаем ответ "не сразу": каждый раз игра должна быть сыграна в соответствии с правилами!

Тот факт, что мы в состоянии дать столь компактную формулировку правил игры, когда единое рассузкдение позволяет нам выводить заключения о любых вариантах игры, непосредственно связан с систематизированным расположением 250000 узловых точек. Мы оказались бы беспомощными, если бы лист картона содержал беспорядочный случайный разброс точек, исключающий какую-либо систематизацию. В нашем случае мы могли бы разделить свою фишку на две половинки и двигать одну половинку вниз, пока она не ляжет на горизонтальную ось, а другую половинку влево, пока она не ляжет на вертикальную ось. Вместо того чтобы воспроизводить с одной фишкой 250 000 возможных положений, мы могли добиться того же с двумя фишками, для каждой из которых нужно только 500 возможных положений, т. е. всего 1000 положений в общей сложности. Мы бы достигли того же уровня в 250 000 позиций, используя то обстоятельство, что любое из 500 положений одной половинки фишки может комбинироваться с любым из 500 положений другой половинки: число положений неразделенной фишки равно произведению числа положений одной половинки на число положений другой. На принятом жаргоне мы говорим, что "общее пространство состояний рассматривается как декартово произведение пространств состояний переменных хну".

Возможность замены одной фишки с двумерной свободой выбора положения на две половинки с одномерной свободой используется в предложенной выше двухрегистровой машине. С точки зрения технической реализации это представляется весьма заманчивым: требуется только построить регистры, способные различать 500 разных случаев ("значений"), а за счет простого объединения этих двух регистров общее число разных случаев возводится в квадрат! Это перемножительное правило позволяет нам различать громадное число возможных общих состояний с помощью ограниченного числа компонентов, у каждого из которых только ограниченное число возможных состояний. По мере добавления таких компонентов размер пространства состояний возрастает экспоненциально, но нам следует иметь в виду, что это допустимо только при условии, что обоснование нашего нововведения остается весьма компактным; если такое обоснование тоже возрастает экспоненциально, то вообще нет никакого смысла создавать такую машину.

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

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

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

Меня завораживает мысль, что эта глава могла писаться еще в времена, когда Евклид мог смотреть на нее из-за моего плеча.

  Оглавление

На первую страницу

Rambler's Top100 Rambler's Top100
PROext: Top 1000

(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz