Организация работы в ИО CLIPS
Порядок работы в ИО CLIPS целесообразно рассмотреть на примере решения несложной логической задачи.
Постановка задачи и составление программы
Постановка задачи. 1. Дан ребус: GERALD + DONALD = ROBERT.
- 2. В словах GERALD, DONALD и ROBERT вместо букв необходимо поставить цифры таким образом, чтобы получилось математически правильное выражение. Разным буквам должны соответствовать разные цифры.
- 3. Требуется написать программу решения ребуса.
Алгоритм решения. 1. Рассмотрим первые разряды всех трех чисел. Считаем, что первый разряд — это единицы, второй разряд — это десятки, третий — сотни и т.д. Очевидно, что нахождение множества пар (буква — цифра), входящих в решение задачи, должно удовлетворять условию:
2. Рассмотрим второй разряд совместно с первым. Необходимо подобрать такие числа L и R, чтобы остаток отделения суммы (L*10 + L*10 + D + D) на 100 был равен (R*10 + Т). При этом следует учесть, что L и R не равны между собой и не равны D и Т.
Таким образом, среди множества пар (буква — цифра), удовлетворяющих первому условию, необходимо найти такие, чтобы:
3. Продолжая действовать подобным образом, можно выписать конечное условие, которому должны удовлетворять пары (буква — цифра), входящие в решение данной задачи.
Решение. Сформулируем описанный ранее подход к решению в терминах CLIPS.
Представим комбинации из одной буквы и одной цифры в виде фактов:
(combination D 0), (combination D 1), (combination А 1) и т.д.
В первую очередь составим правило для нахождения комбинаций (буква — цифра), удовлетворяющих условию (10.1):
- (defrule find_solution (combination D ?d)
- (combination T ?t&~ ?d)
- (test (= (mod (+ ?d ?d) 10) ?t))
=>
- (printout t "A solution is:" t t)
- (printout t ” D = " ?d t)
- (printout t " T = " ?t t))
Данное правило выполнимо только в том случае, если в списке фактов существуют факты, удовлетворяющие условиям:
- 1) (combination D ?d) — все факты, в которых в первой и во второй позициях стоят «combination» и «D» соответственно, а в третьей позиции — любое значение, которое присваивается переменной ?d;
- 2) (combination Т ?t&~ ?d) — все факты, в которых в первой и во второй позициях стоят «combination» и «Т» соответственно, а в третьей позиции — любое значение, только не то, которое было присвоено переменной ?d, это значение присваивается переменной ?t. Знак «&» означает логическое «и» (and), а знак «~» — логическое «не» (not). Выражение «?t&~ ?d» означает, что переменная ?t может принимать значение, не равное значению переменной ?d;
- 3) (test (= (mod (+ ?d ?d) 10) ?t)) — это условие проверяет на равенство два выражения (mod (+ ?d ?d) 10) и ( ?t)).
Команда (printout t "A solution is:" 11) выводит на экран информацию, которая указывается после команды в полях, разделенных пробелами. Чтобы вывести текст, его необходимо заключить в кавычки, а перед кавычками поставить букву t. Эта буква указывает, что в еледующем поле находится текст, взятый в кавычки, который необходимо напечатать. Если после буквы t нет текста в кавычках, то происходит перевод курсора на новую строку.
Перевести курсор на новую строку можно путем указания комбинации символов «crlf» без кавычек. Для вывода значения переменной необходимо просто указать ее имя.
Пример.
printout t " Т = " ?t t)
Оператор выводит текст Т= и значение переменной? t, а затем переводит курсор на новую строку.
Рассмотренное правило позволяет найти все комбинации (буква — цифра), удовлетворяющие условию для первых разрядов трех чисел. По аналогии с этим правилом составим конечное правило для нахождения решения:
- (defrule find-solution (combination D ?d)
- (combination T ?t'?d)
- (test (= (mod (+ ?d ?d) 10) ?t) )
- (combination L ?1&~ ?d&~ ?t)
- (combination R ?r&~ ?d&~ ?t&~ ?1)
- (test (= (mod (+ ?d ?d (* 10 ?1) (* 10 ?1) ?t) ) 100)
- (combination A ?a&~ ?d&~ ?t&~ ?1&~ ?r)
- (combination E ?e&~ ?d&~ ?t&~ ?1&~ ?r&
- (test (= (mod (+ ?d ?d (* 10 ?1) ( (* 100 ?a) (* 100 ?a) )
- 1000)
- (+(* 100 ?e)(* 10 ?r) ?t)))
- (combination N ?n&~ ?d&~ ?t&~ ?i&~ ?r&~ ?a&~ ?&e)
- (combination В ?b&~ ?d&~ ?t&~ ?1&~ ?r&~ ?a&~ ?&e~ ?&n)
- (test (= (mod (+ ?d ?d (* 10 ?1) (* 10 ?1)
- (* 100 ?a) (* 100 ?a) (* 1000 ?r) (*1000 ?n) ) 10000)
- (+ (* 1000 ?b) (* 100 ?e) (* 10 ?r) ?t)
- (combination 0 ?o&~ ?d&~ ?t&~ ?1~ ?r&~ ?a&~ ?e&~ ?n&~ ?b) (combination G ?g&~ ?d&~ ?t&~ ?1&~ ?a&~ ?e&~ ?n&~
- ?b~ ?o)
- (test (= (+ ?d ?d (* 10 ?1) (*10 ?1)
- (* 100 ?a) {* 100 ?a)
- (* 1000 ?r) (* 1000 ?n)
- (10000 ?e) (* 10000 ?o)
- (* 100000 ?q) (* 100000 ?d) )
- (+ (*100000 ?r) (* 10000 ?o) (* 1000 ?b) (* 100 ?e) (*
- 10 ?r) ?t)))
=>
- (printout t "A solution is: " t)
- (printout t "G = " ?g t)
- (printout t "E = " ?e t)
- (printout t "R = " ?r t)
- (printout t "A = " ?a t)
- (printout t "L = " ?1 t)
- (printout t "D = " ?d t)
- (printout t "0 = " ?o t)
- (printout t "N = " ?n t)
- (printout t "B = " ?b t)
- (printout t "T = " ?t t)
- (printout t " " ?g ?e ?r ?a ?1 ?d t)
- (printout t "+" ?d ?o ?n ?a ?1 ?d t)
- (printout t ” " "---------" t)
- (printout t " = ” ?r ?o ?b ?e ?r ?t t t)
Теперь для поиска решения остается занести факты, соответствующие комбинациям из одной буквы и одной цифры, в список фактов. Это можно сделать командой assert:
- (assert (combination D 0) (combination D 1)
- (combination A 1)
- (combination L 9)
...)
Однако, так как количество фактов равно 100, лучше поступить по- другому. Сопоставим буквам и цифрам следующие факты:
- (number 0) , (number 1) , (number 2) , ... , (number 9) ,
- (letter G), (letter E), (letter R), (Letter A),
- (letter L), (letter D), (letter O), (Letter N),
- (letter B), (letter T).
Составим правило, по которому в список фактов будут заноситься факты, соответствующие комбинациям из одной буквы и одной цифры:
- (defrule generate_combination (number ?х)
- (letter ?у)
=>
(assert (combination (?y ?x))))
Согласно данному правилу, если в списке фактов присутствуют факты, имеющие вид (number ?х), (letter ?у), где вместо переменных стоят вполне конкретные значения, в список фактов добавляется еще один факт — (combination ?у ?х), в котором вместо переменных стоят значения из фактов.
Наконец, составим правило, в соответствии с которым, во-первых, на экран будет выводиться условие задачи, а во-вторых, в список фактов будут заноситься факты, соответствующие буквам и цифрам. Поскольку это правило должно выполняться всегда, то его условная часть будет пустой:
(defrule startup
=>
- (printout t t "The problem is" t t)
- (printout t " GERALD" t)
- (printout t ”+ DONALD" t)
- (printout t "------------" t)
- (printout t " = ROBERT" t t)
- (assert
- (number 0) (number 1) (number 2) (number 3) (number 4)
- (number 5) (number 6) (number 7) (number 8) (number 9)
- (letter G) (letter E) (letter R) (letter A) (letter L)
- (letter D) (letter 0) (letter N) (letter B) (letter T)))
Таким образом, рассмотренная программа состоит из трех правил: startup, generate_combination и fmd_solution. Первое из них выводит на экран условие задачи и добавляет в список факты, соответствующие отдельным буквам и цифрам. Второе правило, используя факты, введенные в список фактов первым правилом, заносит в список фактов факты, которые представляют собой всевозможные комбинации из десяти цифр и десяти букв. Третье правило позволяет найти среди этих фактов те, которые удовлетворяют условию задачи, и выводит на экран полученное решение.
Перейдем к порядку выполнения разработанной программы в ПО CLIPS.