Скачиваний:
19
Добавлен:
01.05.2014
Размер:
292.35 Кб
Скачать

Оценка алгоритма планирования

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

Чтение текста программы

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

Соглашения об обозначениях

В программе содержится много процедур, названия которых заканчиваются цифрой "0". Это делается в соответствии с соглашением о том, что такие процедуры вызываются другими процедурами с точно таким же названиями, но без цифры "0" в конце. Например, процедура "построить_список накопит0" вызывается процедурой "построить_список_накопит". Назначение процедуры "построить_список_накопит" состоит в том, что она подготавливает аргументы для процедуры "построить_список_накопит0"; именно процедура "построить_список_накопит0" и выполняет основную работу.

% Программа планирования работы завода

% Соглашения об именах переменных:

% Накоп Наименование накопителя, т.е. 1,2,3,4 или 5

% НакопА, НакопБ НакопБ — это накопитель, располагающийся

% следующим после накопителя НакопА

% Накопители Это список, показывающий, какое

% количество изделий каждого заказа распо-

% лагается в каждом накопителе, т.е. список

% вида: [в (Накоп.Заказы),... ]

% НачНакопители Начальный список накопителей

% ЗакНакопители Заключительный список накопителей (после

% окончания обработки изделий)

% НакопПуть Список, состоящий из списков накопителей,

% по одному на каждый час

% Заказы Список заказов вида: [заказ (ИД, Количество),

% ...I

% ЗаказыХ Список заказов в час Х

% ЗаказыY Список заказов в час Y, где Y = Х + 1

% ЗаказыА Список заказов в накопителе А

% ЗаказыБ Заказы в накопителе Б (Б — это накопитель,

% расположенный вслед за Накопителем А)

% ЗаказыХА Список заказов в час Х в накопителе А

% ИД Уникальный идентификатор заказа

% СписокОпер Список количества операторов, приписанных к

% каждой установке, т.е. список вида:

% [оп(Установка, Количество),...]

% ОпПуть Список, элементами которого являются списки

% "СписокОпер", по одному на каждый час

% НачЧас Начальный час

% ЗакЧас Заключительный час

% Индекс Относительная мера того, насколько много

% работы сделано к концу смены

% ОстПроизводительность Остаточная производительность уста-

% новки в единицу времени после того, как

% был выполнен некоторый объем работ

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ПРОЦЕДУРЫ ИНТЕРФЕЙСА С ПОЛЬЗОВАТЕЛЕМ

%

% СТАРТ (уровень 1; интерфейс с пользователем)

текущий _час (8).

% + старт (Час) :-

retract (текущий _ час (_)),

assert (текущий _ час (Час) ),

nl,печ(' (Час равен '.Час,')'),

%

вводполя (' Нужно ли вводить новое задание? (да или нет) ,

Ответ, нет, элемент (Ответ, [да, нет])),

(Ответ = да, добавить_работу (Час, _) ; Ответ = нет ), ! ,

обработка_смены(меню, план. Час, [],[]).

% ---------------------------------------------------------------

% ОБРАБОТКА СМЕНЫ (уровень 2; интерфейс с пользователем)

% Процедура "обработка_смены" представляет собой самый высокий

% уровень интерфейса с пользователем - цикл опроса пользователя.

% Каждому элементу меню соответствует одно правило.

% Последней подцелью каждого правила является рекурсивный

% вызов данной процедуры.

конец_смены(13). % час, когда заканчивается смена.

% Условие окончания:

% . + + + + +

обработка_ смены (меню, _, Час, НакопПуть, ОпПуть) : -

конец_смены (Час),

печ (' Конец смены в час', Час, . ),

построить_список_накопит (Час, ЗакНакопители),

n1, печ(' Состояние заказов:'),

выдать _посл_ накопители ([ЗакНакопители]), ! .

обработка_ смены (меню, Умалч_знач, Час, НакопПуть, ОпПуть) :-

n1, печ(' (Час равен ', Час,')'), (

Умалч_ знач = план,

печ(' (требуется новый план) ')

;

true

),

печ(' команда? ( план , обработка» помощь - для вывода

списка '),

вводполя (' возможных команд) ',

Ответ, Умалч_знач,

( ОпПуть = [ ], % если список ОпПуть пуст:

( Ответ = план

;

печ(' Вы должны построить план! '),

fail

)

;

ОпПуть \ = = [ ], % если список ОпПуть не пуст:

( элемент (Ответ, [план, обработка, помощь,

' показать работу , ' показать операторов ',

' показать план' , 'конец дня' ])

;

печ (' Вы ошибочно ввели ', Ответ),

печ (' Правильные команды: '),

печ_элем(' ', [план, обработка, помощь,

' показать работу ',

' показать операторов ', ' показать план ',' конец дня ' ]),

fail

)

)

% конец аргумента "Условие" процедуры

% "вводполя" ).

! , обработка_ смены (Ответ, обработка. Час, НакопПуть, ОпПуть).

обработка_смены (план, Умалч_знач, Час, _, _) : -

план_ смены (Час, НакопПуть, ОпПуть),

! , обработка_смены (меню,Умалч_знач, Час, НакопПуть. ОпПуть).

обработка_смены (обработка, Умалч_знач, Час,

[Накопители [ НакопПуть],

[СписокОпер 1 ОпПуть] ) :—

НовЧас is Час + 1,

retract (текущий _ час (Час) ),

assert (текущий _ час (НовЧас)),

% добавить факты "заказ/4" для нового часа:

обработка _ часа (НовЧас, Накопители),

! , обработка_смены(меню, Умалч_знач, НовЧас, НакопПуть, ОпПуть).

обработка _ смены (по мощь, Умалч_знач, Час, НакопПуть, ОпПуть) : —

печ (' Возможные команды: '),

печ_элем(' ',

[' план (составить план на оставшуюся часть смены) ',

' обработка (смоделировать работу за следующий час) ',

' помощь ',

' показать работу (повторно вычислить и показать ',

' текущее состояние заказов) ',

' показать операторов (текущее распределение операторов) ',

' показать план (план на оставшуюся часть смены) ',

' конец дня']),

! , обработка_смены (меню, У малч_знач, Час, НакопПуть, ОпПуть).

обработка_смены (' показать работу ', Умалч_знач, Час,

[Накопители | НакопПуть],

[СписокОпер | ОпПуть] ) : —

% построить список "НовНакопители", чтобы заменить

% список "Накопители" для данного часа:

построить_ список _накопит (Час, ТНакопители),

макс_операторов (Час, МаксОпер),

от_накопит_к_накопит (МаксОпер, ТНакопители, СписокОпер,

НовНакопители),

%

печ(' Заказы на ', Час,' часов '),

write ('Накопитель '),

заголовок_списка_накопит (4),

выдать_список_накопит (ТНакопители),

вводполя (' Нужно ли вводить новое задание? (да или нет) ',

Ответ, нет, элемент (Ответ, [да,нет])),

% (Ответ = да, добавить работу (Час, РабФлаг)

;

Ответ = нет, РабФлаг_нет_ новой работы

),

!,

( РабФлаг = новая работа,

write(' Заказ был добавлен, так как существовал '),

write (' текущий план '), n1,

печ(' Строится новый план ...'),

обработка_смены (план, Умалч_знач, Час, [],[])

;

РабФлаг = нет_новой_работы,

обработка смены (меню, Умалч_ знач. Час,

[НовНакопители | НакопПуть],

[СписокОпер | ОпПуть])

).

обработка_смены(' показать операторов ', Умалч_знач, Час,

НакопПуть, [СписокОпер ! ОпПуть] ) : -

печ(' Операторы в ', Час,' часов '),

выдать_список_операторов (СписокОпер),

write (‘Добавить или удалить операторов? '),

вводполя (' (добавить, удалить, продолжить)

;

Ответ= продолжить,

элемент (Ответ, [добавить, удалить, продолжить] )),

( ( Ответ = добавить ; Ответ = удалить ),

корр_операторов (Час, Ответ)

;

Ответ = продолжить

),

! , обработка_ смены (меню, Умалч_ знач. Час, НакопПуть,

[СписокОпер | ОпПуть]).

обработка _ смены ('показать план ', Умалч_знач, Час, НакопПуть, ОпПуть) :-

n1,

печ(' Текущее распределение операторов: '),

выдать_оп_путь(Час, ОпПуть), n1,

%

конец_ смены (Конец),

write (' приведет к нижеследующему состоянию '),

печ(' заказов ',' к ', Конец,' часам:'),

выдать _ посл _ накопители (НакопПуть),n1,

!, обработка_ смены (меню, Умалч_знач, Час, НакопПуть, ОпПуть).

%-----------------------------------------------------------------------

% СПЛАНИРОВАТЬ СМЕНУ (уровень 3; интерфейс с пользователем)

%

% Построить план на оставшуюся часть смены, начиная с часа

% Час и кончая концом смены

% • + - -

план смены (Час, НакопПуть, ОпПуть) :—

конец _ смены (ЗакЧас),

найти_оптимальное_распределение(Час, ЗакЧас, НачНакопители,

ННакопПуть, НОпПуть),

%

% Переменная НачНакопители содержит описание работы за час

% (перед началом обработки).

n1,

печ (' Нижеследующее распределение операторов: '),

выдать_оп_путь(Час, НОпПуть), n1,

%

печ (' приведет к нижеследующему состоянию заказов ', к ', ЗакЧас, ' часам: ' ),

% вывести последний список накопителей, содержащийся в

% новой переменной НакопПуть:

выдать_посл_накопители (ННакопПуть),n1,

%

печ (' введите принять, если план подходит, или '),

вводполя (' корректировка, если план нужно изменить ',

Ответ, принять,

( элемент (Ответ, [ принять,корректировка ])

;

печ(' неверный ответ '), fail)

), ( Ответ = принять,

НакопПуть = ННакопПуть,

ОпПуть = НОпПуть

;

Ответ = корректировка,

корр_ плана (Час, НачНакопители, ННакопПуть, НОпПуть,

НакопПуть, ОпПуть)

).

%--------------------------------------------------------------------

% ОБРАБОТКА ЧАСА (уровень 3; интерфейс с пользователем)

%

% Добавить факты "заказ" с ненулевыми количествами изделий.

% + +

обработка_ часа (Час, [ в (Накоп,3аказы) | Накопители] ) :-

обработка_ накопителя (Час, Накоп, Заказы),

! , обработка часа (Час, Накопители).

обработка_часа(_, [ ] ).

% + + +

обработка накопителя (Час, Накоп, [заказ (ИД,Количество) ; Заказы])

:-

( Количество \ = = 0,

assert( заказ (Час, Накоп, ИД, Количество))

;

Количество = 0

),

! , обработка_накопителя (Час, Накоп, Заказы).

обработка _ накопителя (_, _, [ ] ).

%-------—------------------------

% ДОБАВИТЬ РАБОТУ (уровень 3; интерфейс с пользователем)

% + -добавить_работу (Час, Флаг) : —

% проверить ИД по списку принятых заказов.

вводполя(' Введите наименование заказа или слово "конец" ',

ИД, конец, true),

( ИД = конец,

Флаг = нет _ новой _ работы

;

ИД \ = = конец,

вводполя ( ' Количество изделий?',

НКоличество, 0, НКоличество > 0),

assert ( заказ (Час, 1, ИД, НКоличество) ),

печ (' Заказ добавлен '),

Флаг = новая _ работа,

добавить_работу(Час, _)

).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ПРОЦЕДУРЫ ПЛАНИРОВАНИЯ

%

% НАЙТИ ОПТИМАЛЬНОЕ РАСПРЕДЕЛЕНИЕ операторов смены.

% (уровень 4; планирование)

% ++---_

найти_оптимальное_распределение (НачЧас, ЗакЧас, _,_,_) :-

% построить начальный список накопителей, НачНакопители:

построить _ список _ накопит (НачЧас, НачНакопители),

assert (оптимальный план (НачНакопители, 0, НачНакопители,

[НачНакопители], [ ])) ,

%

% поиск с возвратом по всем возможным распределениям на

% смену:

найти_ распределение (НачЧас, ЗакЧас, НачНакопители,

ЗакНакопители, НакопПуть, ОпПуть),

индекс_списка_накопителей(ЗакНакопители, Индекс),

оптимальный_план(_, ОптимальныйИндекс, _, _,__),

( Индекс > ОптимальныйИндекс,

один_раз (retract (оптимальный_план (__,_,_,_,_) ) ),

assert (оптимальный _ план (ЗакНакопители, Индекс,

НачНакопители,

НакопПуть, ОпПуть) )

;

Индекс = < ОптимальныйИндекс

), fail.

найти _ оптимальное _ распределение (_, _, Накопители, НакопПуть,

ОпПуть) :-

retract( оптимальный_план(_, _, Накопители,

НакопПуть, ОпПуть) ), ! .

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

% ПОСТРОИТЬ СПИСОК НАКОПИТЕЛЕЙ (уровень 5; планирование)

% Выяснить объем работы на каждом накопителе для часа Час:

% + -

построить_список_накопит(Час, Накопители) :-

findall(S, накопитель (S), S Список),

сп_неповт_знач(ИДО, заказ (_,_, ИДО, _) .СписокИД),

построить_список_накопит0 (Час, СписокИД, S Список, Накопители), ! . построить_список_накопит0(_,_,[],[])

% + + +

построить список _ накопит0 (Час, СписокИД,[S | SСписок],

[ в (S, Заказы) | Накопители]) : -

findаll(заказ (ИД1, Количество),

(элемент (ИД1, СписокИД),

( заказ (Час, S, ИД1, Количество)

;

not( заказ (Час, S, ИД1, Количество) ),

Количество =0 % 0 если отсутствуют факты "заказ"

)

), % конец второго аргумента предиката "findall"

Заказы),

! , построить_ список _накопит0 (Час, СписокИД, SСписок, Накопители).

%___________________________

% ИНДЕКС СПИСКА НАКОПИТЕЛЕЙ (уровень 5; планирование)

% Вычислить значение индекса для списка накопителей. Это значение

% характеризует объем выполненной работы. Для каждого

% накопителя умножить число, являющееся обозначением накопителя,

% на объем работы на этом накопителе.

индекс_ списка_ накопителей ([], 0).

% . +

индекс списка накопителей ([в (Накоп, Заказы) | Накопители],

%

S Индекс) :—

индекс_ списка_заказов (Заказы, Индекс3),

!, индекс списка накопителей (Накопители, SИндекс0),

SИндекс is SИндекс0 + (Накоп * Индекс3):

индекс _ спи ска_ заказов ([ ], 0).

индекс списка заказов ([заказ (_, Количество) | Заказы | , ИндексЗ) :-

!, индекс__списка_ заказов (Заказы, Индекс30),

Индекс3 is Индекс30 + Количество.

%--------------------------------------------------------

% НАЙТИ РАСПРЕДЕЛЕНИЕ (уровень 5; планирование)

%

% Это — базовый блок построения плана. Он вычисляет ОпПуть (т.е.

% распределение операторов на период от НачЧас до ЗакЧас) и

% НакопПуть (т.е. объем работы, который будет выполнен в резуль-

% тате данного распределения операторов). Процедура рекурсивно

% вызывает сама себя один раз на каждый час смены.

% Окончить, если достигнут заключительный час:

% + + +

найти_ распределение (ЗакЧас, ЗакЧас, ЗакНакопители, ЗакНакопители,

% - -

[], []).

найти _ распределение (НачЧас, % + начальный час

ЗакЧас, %+заключительный час

НакопителиХ, % + работа, выполненная за

% предыдущий час

ЗакНакопители, %—работав конце смены

[НакопителиY | НакопПуть], % -

[СписокОпер | ОпПуть ] % -

):-

НачЧас< ЗакЧас,

макс_операторов (НачЧас, МаксОпер),

%

% поиск с возвратом по всем распределениям часа:

распределить__операторов (НачЧас, МаксОпер, НакопителиХ,

СписокОпер),

от _ накопит _к_ накопит (МаксОпер, НакопителиХ, СписокОпер,

Накопители Y),

НовЧас is НачЧас + 1, найти _ распределение (НовЧас, ЗакЧас, НакопителиY,

ЗакНакопители, НакопПуть, ОпПуть).

%---------------------------------------------------------------------------

% РАСПРЕДЕЛИТЬ ОПЕРАТОРОВ (уровень 6; планирование)

%

% По заданному значению переменной "Накопители" (список того,

% как много работы собрано в каждом накопителе) выработать

% значение переменной "СписокОпер" (распределение операторов) -

% Для каждого накопителя осуществляется рекурсивный вызов

% данной процедуры.

распределить _ операторов (Час, % +

Опер, % +операторы, подлежащие

% распределению

[в (НакопА, ЗаказыА) \ Накопители], % спи-

% сок накопителей (+)

[оп(Уст,Чис) [СписокОпер] % —распре-

% деления операторов

) :-Опер > 0, % не пользоваться данным правилом, если 0

% операторов

наименование _ установки (Уст, НакопА, НакопБ),

( пусто (ЗаказыА), % оставшиеся заказы — нулевое коли-

% чество изделий

Чис = 0,

НовОпер is Опер

;

not ( пусто (ЗаказыА) ),

производит _ уст (Уст, Опер, Чис, _), % сгенерировать значение

% переменной "Чис".

%

% послать на установку, по крайней мере, одного оператора,

% если в накопителе НакопА есть работа:

Чис > 0, % не разрешается умалчиваемое значение произ-

% водительности, равное нулю

НовОпер is Опер — Чис

),

распределить_операторов (Час, НовОпер, Накопители, СписокОпер) .

% Приписать к установке 0 операторов, е.сли не осталось свободных

% операторов (нулевое значение второго аргумента) или если список

% ЗаказыА пуст; и списке Накопители (третий аргумент) должно быть

% не менее двух элементов:

распределить_ операторов (Час, % +

0, % +

опер [ в (НакопА, ЗаказыА), % +

в(НакопБ, ЗаказыБ) | Накопители ],

[оп(Уст, 0) | СписокОпер ] % -

) :-

пусто (ЗаказыА),

наименование _ установки (Уст, НакопА, _),

распределить_операторов (Час, 0,

[в (НакопБ, ЗаказыБ) i Накопители],

СписокОпер).

% Следует распределить всех операторов. Процедура "распределить _

% операторов" потерпит неудачу и вернется назад, если значение

% переменной "Опер" (второй аргумент) не равно нулю для последней

% структуры "в (_,_)" в списке накопителей:

распределить_ операторов (_, 0, [в(_ , )], [ ]).

% ПУСТОЙ СПИСОК ЗАКАЗОВ (используется в процедуре

% "распределить_операторов")

% Проверить то, что во всех структурах "заказ (_, _) " имеется

% нулевое количество изделий:

пусто ([ заказ (_,0) [Заказы]) :.—

пусто (Заказы).

пусто([]).

%-----——------------------------------

% ОТ НАКОПИТЕЛЯ К НАКОПИТЕЛЮ (уровень 6; планирование)

% По заданным значениям переменных НакопителиХ (положение

% заказов в час X) и СписокОпер (распределение операторов) вычислить

% значение переменной Накопители Y (положение заказов в час Y,

% гдеY=Х+1).

% На каждый накопитель приходится один рекурсивный вызов данной

% процедуры.

% + + +

от _ накопит _к_ накопит (МаксОпер, НакопителиХ, СписокОпер,

% -

Накопители Y) :—

% построить пустой список "ПрибывающаяРабота":

сп _ неповт _ знач (заказ (ИД, 0), заказ ( _, _, ИД, _ ) ,

Прибывающая Работа),

от _ накопит _ к накопитО (Мак сОпер, Прибывающая Работа,

НакопителиХ, СписокОпер, НакопителиY).

% последний элемент "в(_, _)" в списке накопителей:

от_ накопит _ к _накопит0(_, % +

ПрибывающаяРабота, % +

[в(_,ЗаказыХ)], % +

СписокОпер, % +

[в(_,ЗаказыY)] % -

) :-

от заказа к заказу (0, ПрибывающаяРабота, ЗаказыХ, ЗаказыY), !

от накопит_к_накопит0 (МаксОпер, %+

ПрибывающаяРабота, % +

[в (НакопА,ЗаказыХА) , % + работа час X

в (НакопБ ,ЗаказыХБ) ; НакопителиХ],

СписокОпер, % +

[в (НакопА,ЗаказыYА), % - работа час Y

в (НакопБ ,ЗаказыYБ); НакопителиY]

) :-

% найти значения переменных "Число_опер" и "Установка" для нако-

% пителей А и Б в списке "СписокОпер":

найти_установку (СписокОпер, Установка, НакопА, НакопБ,

Число_опер),

производит_уст (Установка, МаксОпер, Число_опер,

Производительность),

от_заказа_к_заказу (Производительность, ПрибывающаяРабота,

ЗаказыХА, ЗаказыYА,

СделаннаяРабота),

!, от_накопит_к_накопит0 (МаксОпер,

СделаннаяРабота,

[в (НакопБ,ЗаказыХБ); НакопителиХ],

СписокОпер,

[в (НакопБ ,ЗаказыYБ); НакопителиY]) .

% ----------------------------------------------------------------

% ОТ ЗАКАЗА К ЗАКАЗУ (уровень?; планирование)

%

% По заданным значениям переменных "Производительность" (произ-

% водительность установки), "ЗаказыХ" (список работы последнего

% часа) и по списку прибывающей работы, поступающей в виде обра-

% ботанных за этот час изделий, выработать значение переменной

% "ЗаказыY" (новый список работы на следующий час) .

% Осуществляется по одному рекурсивному вызову данной процедуры

% на каждый заказ.

от_заказа_к_заказу (_, [], [], [], [)).

от_заказа_к_ заказу (Производительность, %+

[заказ (Наименование,КоличествоПР) | ПрибывающаяРабота],

% + Прибывающая работа

[заказ (Наименование,КоличествоХ) | ЗаказыХ],

% + Заказы в час Х

[заказ (Наименование.КоличествоY) | ЗаказыY],

% — Заказы в час Y,

[заказ (Наименование,КоличествоСР) | СделаннаяРабота]

% — Сделанная работа

) :-

Производительность > 0,

Фактически_сделано (КоличествоХ, Производительность,

КоличествоСР),

КоличествоY is КоличествоХ — КоличествоСР + КоличествоПР,

ОстПроизводительность is Производительность — КоличествоСР,

!, от_заказа_к_заказу (ОстПроизводительность,

ПрибывающаяРабота, ЗаказыХ, ЗаказыY,

СделаннаяРабота).

!, от_заказа_к_заказу (0, % + Производительность

[заказ (Наименование,КоличествоПР) | ПрибывающаяРабота],

% + Прибывающая работа

[заказ (Наименование,КоличествоХ) | ЗаказыХ],

% + Заказы в

% час Х

[заказ (Наименование.КоличествоY) | ЗаказыY],

% — Заказы в

%часY

[заказ (Наименование, 0) | СделаннаяРабота] % Сделанная работа

) :-%

добавить объем поступившей работы:

КоличествоY is КоличествоХ + КоличествоПР,

% Сделанный объем работ равен нулю:

!, от_заказа_к_заказу(0, ПрибывающаяРабота, ЗаказыХ,

ЗаказыY, СделаннаяРабота).

% _ _ _ _ _ _ _ _ _ _ _

% НАЙТИ УСТАНОВКУ (уровень 7; планирование) %

% По заданному значению переменной "СписокОпер" (список распре-

% деления операторов) и по наименованиям двух накопителей,НакопА

НакопБ, выработать значения переменной Уст (наименование ус-

%тановки, которая обрабатывает изделия, поступающие с НакопА,

% и помещает их в НакопБ) и переменной Чис (число операторов на

% установке).

% + - + +

найти_-установку ([оп (Уст,Чис) | СписокОпер], Уст, НакопА, НакопБ,

%

Чис) :-

наименование_установки (уст, НакопА, НакопБ), !.

найти_установку ([_ | СписокОпер], Уст, НакопА, НакопБ, Чис) :—

найти_установку (СписокОпер, Уст, НакопА, НакопБ, Чис),!.

%----------------------------------------

% ФАКТИЧЕСКИ СДЕЛАННАЯ РАБОТА (уровень 8; планирование)

%

% Если Объем работы меньше имеющейся Производительности,

% то Количество обработанных изделий равно Объему работы,

% в противном случае Количество обработанных изделий равно

% Производительности:

% + + -

фактически—сделано (О, П, К) : — О< 0, К = О, !.

фактически_сделано (О, П, К) :-О-П>0, К=П,!.

фактически„сделано(О,П,К) :-О-П=< 0, К=О,!.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% БАЗЫ ДАННЫХ И ИНТЕРФЕЙСЫ БАЗ ДАННЫХ

%------——-----------------------

% БАЗЫ ДАННЫХ "ПРОИЗВОДИТЕЛЬНОСТЬ УСТАНОВКИ"

% (уровень 7; планирование) %

% Производительность установок в час; Переменная "Число" обозна-

% чает число операторов.

% . +Наим.+ ?

производит_уст (альфа, МаксОпер, Число, Производительность) :—

( % если переменная "Число" не конкретизирована, то

% сгенерировать ее значение:

var (Число), ген_чисел (МаксОпер, Число)

;

nonvar (Число), Число > 0

),

% 5 изделий на оператора в час:

Производительность is Число * 5.

производит_уст (бета, МаксОпер, Число, Производительность) :—

( var (Число),

ген_чисел (МаксОпер, Число)

;

nonvar (Число), Число > О

),

( Число =1, Производительность = 15

;

Число = 2, Производительность = 20

;

Число > 2,

Производительность is 20 + ( (Число — 2) * 2)

% если на установке работает более двух операторов,

% то установка производит по два дополнительных изделия

% на каждого оператора сверх двух.

).

производит_уст (гамма, _, Число, Производительность) :-

% на установке "гамма" должны работать ровно два оператора:

( var (Число), Число = 2

;

nonvar (Число), Число >= 2

),

Производительность = 20.

производит—уст (дельта, МаксОпер, Число, Производительность) :—

( var (Число), ген_чисел (МаксОпер, Число)

;

nonvar (Число) , Число > О

),

% 8 изделий на оператора в час:

Производительность is Число * 8.

% умалчиваемое значение:

производит_уст(_, _, 0,0).

%-------------------------------

% МАКСИМАЛЬНОЕ ЧИСЛО ОПЕРАТОРОВ

% (уровень 6; планирование) % + _

макc_операторов (Час, Число) :—

% построить список операторов, все еще находящихся на работе

% в течение часа "Час":

findall(X, послать (Час, оператор (X) ), Список),

length(Список,Число),!. %_____________________________________________________________________

%БАЗА ДАННЫХ "ОПЕРАТОР" (уровень 7; планирование)

% Данные факты вводятся в программу интерфейсом с таймером.

% 8 = 8 часов утра (время прихода оператора на работу)

оператор (8, джек).

оператор (8, марта).

оператор (8, сюзан).

оператор(8,барни).

оператор (8, фред).

% дуг приходит позже:

% оператор (9, дуг).

% барни и фред уходят с работы в 11.00:

% опровергнуть(11,оператор(8,барни)),

% опровергнуть (11, оператор (8, фред) ).

%_____________________________________________________________________

% БАЗА ДАННЫХ "НАКОПИТЕЛЬ" (уровень 6; планирование)

% Накопитель — это место, где накапливаются изделия перед обработ-

% кой на установке и после обработки.

% 1 == совершенно не обработано;

% 5 == обработка закончена.

накопитель (1). % начало.

накопитель (2).

накопитель (3).

накопитель (4).

накопитель (5). % конец.

%_____________________________________________________________________

% БАЗА ДАННЫХ С НАИМЕНОВАНИЯМИ УСТАНОВОК

% (уровень 7; планирование)

% установка "альфа" обрабатывает детали, поступающие из накопителя

% 1 и помещает обработанные детали в накопитель 2:

наименование_установки (альфа, 1, 2).

наименование_установки (бета, 2, 3).

наименование_установки (гамма, 3, 4),

наименование_установки (дельта, 4, 5).

%_____________________________________________________________________

% БАЗА ДАННЫХ "ЗАКАЗ" (уровень 6; планирование)

% Каждый заказ, подлежащий обработке, представляется в программе

% в виде фактов нижеследующей формы:

% Час Накопитель ИД Изделий

заказ(8, 1, доу, 18).

заказ(8, 1, ' макгроу, 25).

%_____________________________________________

% БАЗА ДАННЫХ С ИНФОРМАЦИЕЙ О ВРЕМЕНИ

%

% Данная база данных позволяет процедуре "послать" находить кор-

% ректное число операторов для заданного часа.

порождение (9, 8).

порождение (10, 9).

порождение (11, 10).

порождение (12, 11).

порождение (13, 12).

порождение (14, 13).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ПРОЦЕДУРЫ ВЫВОДА ИНФОРМАЦИИ

%

% ВЫДАТЬ ОП ПУТЬ (уровень 3; вывод)

% Вывести распределения операторов по часам рабочей смены.

выдать_оп_путь( , []).

выдать_оп путь (Час, [СписокОпер ! ОпПуть]) :—

length (СписокОпер, Чис), % Чис = число установок.

write (' Час '),

оп _путь_заголовок (Чис).

выдать_оп_путь0 (Час, [СписокОпер! ОпПуть]).

оп_путь_заголовок (0) :— nl. % переход к новой строке.

оп_путь_заголовок (Длина) :—

Длина > 0,

write (' Уст. On. '),

НовДпина is Длина — 1,

оп_путь_заголовок (НовДпина).

выдать_оп_путь0 (_, [ ] ) .

выдать—оп_путь0 (Час, [СписокОпер \ ОпПуть]) :—

write (Час), write (' '), % табуляция

выдать_список_операторов (СписокОпер),

НовЧас is Час + 1,

Выдать_oп_путь0 (НовЧас, ОпПуть) .

выдать_список_операторов ([]):— nl. % переход к новой строке.

выдать_список_операто ров ([оп (Установка,Опер) | СписокОпер]) :—

write (Установка), write (' '), % табуляция

write (Опер), write (' '),

выдать_список_операторов (СписокОпер).

%_____________________________________________________________________

% ВЫДАТЬ ПОСЛЕДНИЙ СПИСОК НАКОПИТЕЛЕЙ

% (уровень 3; вывод)

%

% Перейти к последней переменной "Списки", а затем вызвать про-

% цедуру "выдать список_накопит"

выдать_посл_накопители ([Накопители 1 НакопПуть] ) :-

НакопПуть \ == [ ],

выдать_посл_накопители (НакопПуть).

выдать_посл_накопители( [Накопители]) :— % последний элемент

% списка "НакопПуть".

write (' Накопитель ' ),

заголовок_списка„накопит (4),

выдать_список„накопит (Накопители).

заголовок_списка__накопит (0) :— nl.

заголовок_списка_накопит (Длина) :—

Длина > 0,

write (' Идентификатор Кол-во '),

НовДпина is Длина — 1,

заголовок_списка_накопит(НовДлина).

%_____________________________________________________________________

% ВЫДАТЬ СПИСОК НАКОПИТЕЛЕЙ (уровень 4; вывод)

%

выдать_список_накопит( [ ]).

выдать_список_накопит ([в (Накоп.Заказы); Накопители]) :-

write (Накоп), write (' '), % табуляция

выдать_список_заказов (Заказы), nl,

выдать_список_накопит (Накопители).

выдать_список_ заказов ([ ]).

выдать_список_заказов ([заказ (ИД,Количество); Заказы]) :-

write (ИД), write (' '),

write (Количество), write (' '),

выдать_список_заказов (Заказы).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ПРОЦЕДУРЫ КОРРЕКТИРОВКИ

%

% КОРРЕКТИРОВКА ОПЕРАТОРОВ (уровень 3; корректировка)

корр_операторов (Час, добавить) :—

write (' Введите имя оператора или слово "конец" '),

вводполя (' для продолжения работы ',

Ответ, конец, true),

( Ответ = конец

;

Ответ \ == конец,

assert (оператор (Час, Ответ) ),

write (' Оператор добавлен '),

корр„операторов (Час, добавить)

).

корр_операторов (Час, удалить) :—

write (' Введите имя удаляемого оператора или '),

вводполя (' слово "конец" ', Ответ, конец, true),

( Ответ = конец

;

Ответ \ == конец,

assert ( опровергнуть (Час, оператор (_, Ответ)) ),

write (' Оператор удален '),

корр_операторов(Час,удалить)

).

%_______________________________________________________________

% КОРРЕКТИРОВКА ПЛАНА (уровень 4; корректировка)

корр_плана (Час, %+

НачНакопители, %+ работа для часа "Час"

[НакопителиХ ! НакопПутьХ], % + текущ. НакопПуть

[СписокОперХ; ОпПутьХ], %+ текущ. ОпПуть

[НакопителиY [ НакопПутьY], % — откорр. НакопПуть

[СписокОперY ; ОпПутьY] % - откорректир. ОпПуть

) :-

корр_списка_опер(Час, НачНакопители, НакопителиY,

СписокОперХ, СписокОперY),

НовЧас is Час + 1,

корр_плана (НовЧас, НакопителиY, НакопПутьХ, ОпПутьХ,

НакопПутьY, ОпПутьY).

% значение переменной "НакопителиY" вырабатывается процеду-

% рой, "корр_списка_опер" и является вторым аргументом

% при рекурсивном вызове

корр_плана (Час, НачНакопители, [ ], [ ], [ ], [ ]) :—

nl.

печ (' Планируемая работа завода к концу смены: '),

write (' Накопитель ' ),

заголовок_списка_накопит(4),

выдать_список_накопит(НачНакопители),!.

%________________________________________________________________

% КОРРЕКТИРОВКА СПИСКА ОПЕРАТОРОВ (уровень 5; корректировка)

%

% интерфейс с процедурой "корр_списка_опер0".

% + + _ +

корр_списка_.опер(Час, НачНакопители, НовНакопители, СписокОперХ,

%

СписокОперY) : -

n1,

печ(' Планируемая работа завода на ', Час, ' часов: '),

write (' Накопитель ),

заголовок_списка_накопит (4),

выдать_список_накопит (НачНакопители),

%

n1,

печ (' Текущее распределение операторов: ' ),

выдать_список_операторов (СписокОперХ),

n1,

%

макс_операторов (Час, МаксОпер),

корр_списка_опер0 (МаксОпер, СписокОпер, СписокОперY),

%

% вычислить значение переменной "НовНакопители" (резуль-

% тат нового распределения операторов) :

от_накопит_к_накопит (МаксОпер, НачНакопители,

СписокОперУ, НовНакопители) .

корр_списка_опер(_, _, [ ], [ ], [ ]).

% КОРР_СПИСКА_ОПЕРО

% Корректировать все распределения операторов для заданного часа. корр_списка_опер0 (МаксОпер, %+

[оп (Уст,ЧисХ) | СписокОперХ], %+

[оп (Уст,ЧисY) | СписокОперY] %-

):-

наименование_установки (Уст, НакопА, НакопБ),

печ(' Установка: ', Уст, ' между ', НакопА, ' и ',

НакопБ, ' '),

% проверить новое значение:

вводполя (' Количество операторов: ', ЧисY, ЧисХ,

( ЧисY > = 0, ЧисY =< МаксОпер ) ) ,

!, корр_списка_опер0 (МаксОпер, СписокОперХ,

СписокОперY).

корр списка_опер0 (—, [], []):—!.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% ПРОЦЕДУРЫ ВВОДА-ВЫВОДА НИЗКОГО УРОВНЯ

% ПЕЧАТЬ

% Печать от одного до семи аргументов и перевод строки:

печ(А) :—write(A), nl,

печ (А, Б) :-writf(A),write(Б),nl.

печ(А,Б,В) :-write(A),write(Б),write(B), nl.

печ (А, Б, В, Г) :-write(A),write(Б),write(B),write(Г),nl.

печ(А, Б, В, Г, Д) :- write(A), write (Б), write(B),

write (Г), write (Д),n1.

печ(А, Б, В, Г, Д, Е) :- write(A), write (Б), write(B), write (Г),

write(Д), write (E),nl.

печ(А, Б, В, Г, Д, Е, Ж) :- write(A), write (Б), write(B), write (Г) ,

write (Д), write (Е), write (Ж), nl.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% РАЗЛИЧНЫЕ ПРОЦЕДУРЫ

%

% ПЕЧАТЬ ЭЛЕМЕНТОВ

печ_элем (Смещение, [A | R]) :-

write (Смещение), write(A), nl,

печ _элем (Смещение, R).

печ_элем(_, []).

% ГЕНЕРАТОР ЧИСЕЛ

% Сгенерировать целое число N из диапазона от 1 до Макс, включая

% границы диапазона:

ген_чисел (Макс, N) :-

ген_чисел0 (Макс, 1, N).

ген_чисел0 (Макс, Начало, Начало).

ген_чисел0 (Макс, Начало, N) :—

НовНачало is Начало + 1,

НовНачало =< Макс,

ген_чисел0 (Макс, НовНачало, N).

% СУММА СПИСКА ЧИСЕЛ

сумма([], 0).

сумма ([F \ R], Итог) :-

сумма (R, Врем),

Итог is F + Врем.

% ЧИСТКА

чистка :- % избавиться от всех заказов, добавленных после

% 8 часов утра.

заказ (Час, А, Б, В),

Час>8,

retract (заказ (Час, А, Б, В) ), fail.

чистка :— % переустановить часы

retract (текущий_час (_) ),

assert (текущий_час (8) ).

% ИСПОЛЬЗУЕМЫЙ ФАЙЛ

:-consult(' послать '). % механизм наследования

Соседние файлы в папке Гл.6,7,Прилож.,Допол