------------------------------------------------------------------------ -- An example of visual expert system. -- -- The program is written on Actor Prolog. -- -- (c) Alexei A. Morozov, March 19, 1999. -- ------------------------------------------------------------------------ -- This is my favorite program. It helps to cook black rowan, apple, -- -- and strawberry jam. Actually I wrote this program to train myself -- -- in carrying out SADT interview. For that I have asked my mother -- -- to tell me how one should cook a jam. I made an effort to draw -- -- the model as detailed as possible; thus the interview has -- -- lengthened about two days. The result was unexpected for both of -- -- us. My mother was very surprised when I have showed her the total -- -- list of cooking battery that she usually uses for cooking ordinary -- -- jam. Besides I have learned to cook a little. -- -- Mother, thank you for the help! -- ------------------------------------------------------------------------ -- A logical description of the blocks of the SADT model. -- ------------------------------------------------------------------------ -- This class is simply a dummy. It opens a dialog box for -- -- choosing berries and fruits. -- ------------------------------------------------------------------------ class 'CHOOSE_BERRIES_AND_FRUITS' specializing 'DIALOG': value_o1; identifier= "ChooseFruits"; [ ] ------------------------------------------------------------------------ -- The following classes correspond to blocks of the SADT model. -- -- The main purpose of these classes is keeping lists of cooking -- -- battery corresponding to various blocks of the SADT model. -- -- In addition to this purpose some blocks implement the following -- -- functions: -- -- 1) They transmit some values (names of selected berries and -- -- fruits) from an input to the outputs of block. -- -- 2) They check if selected berries and fruits are conformed to -- -- given block. If they do not conform, then the execution of the -- -- 'goal' actor is terminated with failure and the process changes -- -- its state to "failed". In this case the color of corresponding -- -- block on the screen becomes red. -- -- 3) They calculate suggested period of the heat of sugar mixture -- -- for selected berries and fruits. -- -- The classes corresponding to compound blocks are descendants of -- -- the 'Compound_Block' class. The destination of this class we will -- -- discuss later in the course of consideration of the "Analysis of -- -- model" block. -- ------------------------------------------------------------------------ class 'WASH_UP_JARS_AND_LIDS' specializing 'Simple_Block': [ ] ------------------------------------------------------------------------ class 'BOIL_SOME_WATER_IN_A_KETTLE' specializing 'Simple_Block': [ instrument()= "A kettle". ] ------------------------------------------------------------------------ class 'CLEANSE_LIDS_BY_BOILING_WATER' specializing 'Simple_Block': [ instrument()= "A saucepan for boiling water". ] ------------------------------------------------------------------------ class 'CLEANSE_JAM-JARS_BY_BOILED_WATER' specializing 'Simple_Block': [ instrument()= "A kettle". ] ------------------------------------------------------------------------ class 'DRY_JAM-JARS_AND_LIDS' specializing 'Simple_Block': [ ] ------------------------------------------------------------------------ class 'WASH_BERRIES_AND_FRUITS' specializing 'Simple_Block': value_i1; protecting: value_o1; [ goal:-!, value_o1 == value_i1. -- instrument()= "A colander". ] ------------------------------------------------------------------------ class 'PREPARE_SOME_MIXTURE_OF_HARD_BERRIES_AND_SUGAR' specializing 'Compound_Block': value_i1; [ goal:-!, check_fruits(value_i1). -- check_fruits("Black rowan"). ] ------------------------------------------------------------------------ class 'PREPARE_SOME_MIXTURE_OF_LARGE_FRUITS_AND_SUGAR' specializing 'Compound_Block': value_i1; [ goal:-!, check_fruits(value_i1). -- check_fruits("The \"Antonovka\" apples"). ] ------------------------------------------------------------------------ class 'PREPARE_SOME_MIXTURE_OF_SOFT_BERRIES_AND_SUGAR' specializing 'Compound_Block': value_i1; [ goal:-!, check_fruits(value_i1). -- check_fruits("Strawberry"). ] ------------------------------------------------------------------------ class 'BOIL_SOME_WATER_IN_THE_SAUCEPAN' specializing 'Simple_Block': [ instrument()= "A saucepan for boiling water". ] ------------------------------------------------------------------------ class 'PREPARE_SOME_SYRUP' specializing 'Simple_Block': value_i1; value_o1; [ goal:-!, value_o1 == value_i1. -- instrument()= "A saucepan or copper basin". instrument()= "Wooden spoon". ] ------------------------------------------------------------------------ class 'BLANCH_BERRIES' specializing 'Simple_Block': value_i2; value_o1; [ goal:-!, value_o1 == value_i2. -- instrument()= "A colander". instrument()= "A saucepan for boiling water". ] ------------------------------------------------------------------------ class 'PUT_BERRIES_IN_SYRUP' specializing 'Simple_Block': value_i1; value_o1; [ goal:-!, value_o1 == value_i1. -- instrument()= "A saucepan or copper basin". ] ------------------------------------------------------------------------ class 'CUT_FRUITS_INTO_LOBULES' specializing 'Simple_Block': value_i1; value_o1; [ goal:-!, value_o1 == value_i1. -- instrument()= "A knife of stainless steel". ] ------------------------------------------------------------------------ class 'SPRINKLE_WITH_SUGAR' specializing 'Simple_Block': value_i1; value_o1; [ goal:-!, value_o1 == value_i1. -- instrument()= "A saucepan or copper basin". ] ------------------------------------------------------------------------ class 'SUSPEND_THE_PROCESS_FOR_6-8_HOURS' specializing 'Simple_Block': value_i1; value_o1; [ goal:-!, value_o1 == value_i1. -- instrument()= "A saucepan or copper basin". ] ------------------------------------------------------------------------ class 'ADD_SOME_WATER_IN_THE_MIXTURE' specializing 'Simple_Block': value_i1; value_o1; [ goal:-!, value_o1 == value_i1. -- instrument()= "A saucepan or copper basin". ] ------------------------------------------------------------------------ class 'BOILING_CYCLE_FOR_HARD_BERRIES_AND_FRUITS' specializing 'Compound_Block': value_i1; [ goal:-!, check_fruits(value_i1). -- check_fruits("Black rowan"). check_fruits("The \"Antonovka\" apples"). ] ------------------------------------------------------------------------ class 'BOILING_CYCLE_FOR_SOFT_BERRIES_AND_FRUITS' specializing 'Compound_Block': value_i1; [ goal:-!, check_fruits(value_i1). -- check_fruits("Strawberry"). ] ------------------------------------------------------------------------ class 'HEAT_THE_MIXTURE' specializing 'DIALOG': value_i2; time; identifier = "HeatUpMixture"; fruits = value_i2; [ goal:-!, set_time(value_i2,time). -- set_time(#,"3-5"):-!. set_time("Black rowan","3"):-!. set_time("The \"Antonovka\" apples",5):-!. set_time("Strawberry","---"):-!. set_time(_,"3-5"):-!. -- instrument()= "A saucepan or copper basin". instrument()= "Wooden spoon". ] ------------------------------------------------------------------------ class 'SUSPEND_THE_PROCESS' specializing 'Simple_Block': [ instrument()= "A saucepan or copper basin". ] ------------------------------------------------------------------------ class 'CHECK_IF_JAM_IS_READY' specializing 'Simple_Block': [ instrument()= "Wooden spoon". instrument()= "A saucer". ] ------------------------------------------------------------------------ class 'MAIN_PHASE_OF_BOILING' specializing 'DIALOG': value_i1; time; identifier = "HeatUpMixture"; fruits = value_i1; [ goal:-!, set_time(value_i1,time). -- set_time(#,"---"):-!. set_time("Strawberry","10"):-!. set_time(_,"---"):-!. -- instrument()= "A saucepan or copper basin". instrument()= "Wooden spoon". ] ------------------------------------------------------------------------ class 'SUPPLEMENTARY_PHASE_OF_BOILING' specializing 'Simple_Block': [ instrument()= "A saucepan or copper basin". instrument()= "Wooden spoon". ] ------------------------------------------------------------------------ class 'COOL_JAM' specializing 'Simple_Block': [ instrument()= "A saucepan or copper basin". ] ------------------------------------------------------------------------ class 'POUR_JAM_INTO_JARS' specializing 'Simple_Block': [ instrument()= "Wooden spoon". instrument()= "Canning equipment". ] ------------------------------------------------------------------------ class 'Simple_Block': [ goal. -- show(_). ] ------------------------------------------------------------------------ -- This block creates and demonstrates total list of cooking battery -- -- necessary for jam-making with chose berries and fruits. -- -- This block implements the following idea: -- -- 1) The values of the "container" slots are created automatically -- -- during the translation of the SADT diagrams. This slot contains -- -- a process corresponding to the block that contains the given -- -- block. It is the "JAM-MAKING" block. A special resident proves -- -- the 'instrument' predicate in this block. -- -- 2) The "JAM-MAKING" block as well as other compound blocks are -- -- implemented on the basis of the 'Compound_Block' class in the -- -- course of translation of the SADT model. The 'Compound_Block' -- -- class is an ancestor of corresponding classes. -- -- 3) The 'Compound_Block' class is defined in the text of the -- -- program. At the same time there is the 'instrument' function -- -- that must be defined in the 'Compound_Block' class. The result -- -- calculated by this function is a result of the 'component' -- -- function. -- -- 4) The 'component' function is non-deterministic one. It is -- -- defined automatically during the translation of compound -- -- blocks. The results calculated by this function are processes -- -- that correspond to the blocks that are internal components of -- -- given compound block. -- -- 5) Thus the "Analysis of model" block gets a list of processes -- -- corresponding to the neighboring blocks with the help of a -- -- resident. -- -- 6) Obtained list is transmitted to other resident in the recursive -- -- definition of the process 'Instruments'. This process proves -- -- the same 'instrument' predicate in these worlds. -- -- 7) In the case if the 'instrument' predicate is proven in a simple -- -- block, the corresponding process returns a list of cooking -- -- battery related to given block. In the case if the predicate is -- -- proven in a compound block, the execution of the predicate -- -- occurs to be the same as in the "JAM-MAKING" block considered -- -- above. Thus the resident computes a list containing cooking -- -- battery as like as processes corresponding to some internal -- -- blocks. -- -- 8) Created list is transmitted to the next level of recursion and -- -- processed by the next resident. This recursive processing -- -- continues till the list is not refined on the given stage of -- -- recursion. If the input list is equal to the output list on -- -- given stage of recursion, then the examination of the tree of -- -- blocks has reached all the leafs of the tree. In this case -- -- there are no more processes in the list of cooking battery. -- -- 9) Processed list of cooking battery is sorted and demonstrated -- -- in the dialog box. -- ------------------------------------------------------------------------ class 'ANALYSIS_OF_MODEL:_WHAT_KITCHEN_UTENSILS_ARE_WE_NEED?' specializing 'DIALOG': -- identifier= "ListOfInstruments"; -- title; name; number; model; x; y; text_color; container; con; -- result; instruments; -- agent = (('FindInstruments', container, protecting: result)); [ goal:- refine_list(result,[],instruments),!. goal:-!, [result]. -- refine_list([],List,List):-!. refine_list([#|Rest],List1,List2):-!, refine_list(Rest,List1,List2). refine_list([Item|Rest],List1,List3):- is_list(Item),!, refine_list(Item,List1,List2), refine_list(Rest,List2,List3). refine_list([Item|Rest],List1,List2):- is_not_element(Item,List1),!, refine_list(Rest,[Item|List1],List2). refine_list([_|Rest],List1,List2):-!, refine_list(Rest,List1,List2). refine_list(_,List,List). -- is_list([]):-!. is_list([_|_]). -- is_not_element(_,[]):-!. is_not_element(Item,[Item|_]):-!, fail. is_not_element(Item,[_|List]):- is_not_element(Item,List). -- show(_):- show. ] ------------------------------------------------------------------------ class 'FindInstruments' specializing 'ALPHA': container; result; agent = (('Instruments', suspending: source_list= [], target_list= container, protecting: result )); [ goal:-!. ] ------------------------------------------------------------------------ class 'Instruments' specializing 'Alpha': source_list; target_list; result; -- tail_list; tail_result; tail = (('Instruments', suspending: source_list=tail_list, target_list=target_list ?? instrument(), protecting: result=tail_result )); con = ('Console'); [ goal:- source_list == target_list,!, result == target_list. goal:- tail_list== target_list, result== tail_result. ] ------------------------------------------------------------------------ class 'Compound_Block' specializing 'Alpha': c = ('Console'); [ instrument()= Block :-!, component(Block). ] ------------------------------------------------------------------------ |