Данные и предложения для тестирования
test_lee(Name,Path)
data(Name,A,B, Obstacles).
lee_route(A,B,Obstacles,Path).
data(test, 1 - 1,5 - 5, [obstacles(2 - 3,4 - 5), obstacles(6 - 6,8 - 8)]),
Программа 17.6.Программа трассировки по алгоритму Ли.
тельные волны - это множества точек сетки, соседние с точками предыдущей волны и не попавшие в предыдущие волны. Это определение иллюстрируется изображением волн на рис. 17.3тонкими сплошными линиями.
Генерация волн осуществляется с помощью предиката waves (В,WavesSoFar, Waves),который определяет список волн Waves,достигнувших конечной точкиВ. Параметр WavesSoFar -накопитель волн, образованных с начала их генерации от исходной точки к текущему шагу. Вычисления по этому предикату завершаются, когда текущая волна накроет конечную точку. В теле предложения wavesиспользуется предикат next_wave,в котором для поиска соответствующих точек сетки применены множественные выражения.
Предполагается, что препятствия являются прямоугольными блоками. Для их представления используется терм obstacle (L,R),где L-координаты левого нижнего угла, R-координаты правого верхнего угла блока. В упражнении к этому разделу предлагается изменить программу так, чтобы она допускала обработку препятствий другой формы.
Предикат find_path(А,В,Waves,Path)используется для нахождения обратного пути PathизВвАпо сгенерированным ранее волнам. При построении пути производится спуск вниз в соответствии с порядком точек отВкА.Этот порядок можно изменить, используя в предикате find_pathнакопитель.
В процессе нахождения пути по алгоритму Ли вывод даных в программе 17.6не предусмотрен. На практике пользователь может пожелать увидеть результаты текущих вычислений. Это легко осуществить добавлением соответствующих операторов writeв процедуры next_waveи find_path.
В последнем примере этого раздела решается задача поиска ключевых слов в контексте. И вновь объединение недетерминированного программирования с программированием второго порядка позволяет с помощью простой Пролог-программы решить сложную задачу.
Нахождение ключевых слов в контексте связано с поиском всех вхождений множества ключевых слов в определенный текст и выделением контекстов, в которых они встречаются. Здесь будет рассмотрен следующий вариант этой общей задачи: «Для данного списка заголовков сформировать упорядоченный список всех вхождений в данные заголовки множества ключевых слов вместе с их контекстами».
Пример входных и ожидаемых выходных данных для такой программы представлен на рис. 17.4.Контекст описывается как вращение заголовка, конец которого отмечен вертикальной чертой «|».В рассматриваемом примере использован следующий набор «нетривиальных» ключевых слов: algorithmic, debugging, logic, problem, program, programming, prologи solving.
В данной задаче подлежит вычислению отношение k^-ic(Titles,KmcTil1es},гдеTub's-список заголовков, из которых должны быть выделены ключевые слова, а
Вход: programming in prolog logic for problem solving logic programming algorithmic program debugging
Выход: algorithmic program debugging |, debugging | algorithmic program, logic for problem solving |, logic programming, |, problem solving | logic for, program debugging | algorithmic, programming in prolog |. programming | logic, prolog | programming in, solving | logic for problem
Рис17.4.Вход и выход для задачи поиска вхождений ключевых слов в контексте.
КwicTitles-отсортированный список ключевых слов в их контекстах. Предполагается, что входной и выходной тексты представлены в виде списков слов. В более общей программе должны быть предусмотрены предварительный шаг преобразования входного текста в свободной форме в списки слов, а также выдача результатов в удобном для чтения виде.
Рассмотрим поэтапное представление программы. Основа программы - недетерминированное описание вращения списка слов. С помощью предиката appendему можно дать следующее элегантное определение:
rotate(Xs,Ys) append(As,Bs,Xs). append! Bs,As.Ys),
Декларативно: Ys - вращение Xs,если Xsсостоит из As,за которым следует Bs,аYs состоит из Bs,за которым следует As.
Следующий этап связан с идентификацией отдельных слов как потенциальных ключевых слов. Это выполняется посредством выбора слова в первом вызове предиката append.Отметим, что следующее новое правило является примером предыдущего правила rotate:
rotate(Xs,Ys) append(As.[Key | Bs],Xs), append([Key | Bs].As,Ys).
Кроме того, это определение лучше предыдущего, поскольку в нем предусмотрено удаление одинаковых решений, когда один из расщепленных списков пуст, а другой -полон.
Следующее улучшение связано с более детальной проверкой потенциального ключевого слова. Предположим, что каждое ключевое слово Wordопределяется фактом вида keyword(Word).Решения в процессе rotateмогут быть отфильтрованы так, чтобы воспринимались только те слова, которые идентифицированы как ключевые. Соответствующая версия рассматриваемого предложения имеет вид
rotate_and_filter(Xs,Ys)
append(As,[Key| Bs],Xs), keyword(Key), append([Key | Bs],As,Ys).
Операционное поведение данной процедуры: она рассматривает все ключевые слова, отфильтровывая нежелательные альтернативы. Для максимизации эффективности программы в данном случае важен порядок целей.
В программе 17.7,окончательной версии интересующей нас программы, предусмотрены дополнительные средства для распознавания ключевых слов. Любое слово Wordсчитается ключевым, если оно не специфицировано с помощью факта вида insignificant(Word) какнезначащее. Кроме того, в процедуре выполняется вставка в конец заголовка маркера «|»,отмечающего контекстную информацию. Это реализуется добавлением дополнительного символа во втором обращении к предикату append.Соответствующее предложение rotate_and_filterсодержится в программе 17.7.
Наконец, для получения всех решений использован множественный предикат. Квантификация необходима ло всем возможным заголовкам. Явным преиму-
kwic(Tites,КWTitles)
КWTities-KWIC-инлскссписка заголовков Titles.
kwic(Titles.KWTilles)
set_of(Ys,Xs (member(Xs, Titles),
rotate_and_fiIter(Xs,Ys)),KWTitles).
rotate_and_filter(Xs, Ys)
Ys-вращение списка Xs,такое, что первое слово Ys значимо, и знак '|' вставлен после последнего слова Xs.
rotate_and_filter(Xs,Ys)
append (As, [Key | Bs],Xs),
not insignificant(Key),
append([Key,’|’ | Bs],As,Ys).