% PARTS INVENTORY: the basic database consists of the collection of basic % parts together with the list of compound parts followed by their immediate % components. We need to find a type and quantity of basic parts needed to % assemble more complex once. More precisely, we assume that our basic % database contains a complete list of basic parts, e.g. basic_part(rim). basic_part(nut). basic_part(spoke). basic_part(frame). basic_part(brakes). basic_part(tire). % All other symbolic names used in the database will be understood as names % of compound parts. We will also use integers. By "lists of parts" we mean % a list of the form [[P1,K1]...[Pn,Kn]] where P's are parts and K's are % positive integers. [P,K] is read as "K items of the part P". If all P's of % list L are basic parts we say that L is a list of basic parts. A list of parts % will be called canonical if it has at most one occurrence of any part P. % We assume that the basic database contains a complete list % of compound facts together with information about the names % names and quantities of their immediate components, e.g. components(bike,[[wheel,2],[frame,1],[steering,1] ]). components(wheel,[[spoke,4],[rim,1],[tire,1],[nut,5]]). components(steering, [ [brakes,2], [nut,10] ]). % The second parameter of this relation is a canonical list of parts. % We are interested in defining a relation parts_required(N,P,L) % which satisfies the following two conditions: % 1. For any positive integer N and a part P there is a canonical % list L of basic parts such that parts_required(N,P,L) is true. % 2. If parts_required(N,P,L) holds then L is a canonical list of basic % parts required to assemble N parts of type P. % We start our design with defining parts_required(N,P,L) % with the mode parts_required(+,+,-) % The definition is given by two rules parts_required(N,P,[[P,N]]) :- basic_part(P). parts_required(N,P,L) :- components(P,C), parts_for_list(C,L1), times(N,L1,L). % where the relation parts_for_list(C,L) satisfies the following % two conditions: % 1. For any list C of parts there is a canonical list L of basic % parts such that parts_for_list(C,L) holds. % 2. If parts_for_list(C,L) holds then L is a canonical list of % basic parts required to assemble parts from C. % and % the relation times(N,L1,L2) constructs the list L2 by replacing % every element [P,M] of L1 by [P,N * M]. % To define parts_for_list(C,L) with mode parts_for_list(+,-) % we need the following rules: parts_for_list([ ],[ ]). parts_for_list([[P,K]|T],L) :- parts_required(K,P,Lp), parts_for_list(T,Lt), combine(Lp,Lt,L). % Here combine(L1,L2,L) is a new relation which appends two % canonical lists L1, L2 of parts, transforms the result into % a canonical form and stores it in L. %mode - combine(+,+,-) combine([],L,L). combine([[P,N1]| T], L1, L) :- append(R1,[[P,N2]|R2],L1), N is N1 + N2, append(R1,[[P,N]|R2],L2), combine(T,L2,L). combine([[P,N]| T], L1, [[P,N] | L]) :- combine(T,L1,L). % To complete the assignement we define the relation times. %times(N,L1,L2) satisfies the following conditions: % 1. For any positive number N and a list L1 of parts there is % a list L2 such that times(N,L1,L2) holds. % 2. If times(N,L1,L2) holds then [P,K] is in L2 iff [P,K/N] is in L1. %mode times(+,+,-) times(_,[],[]). times(N,[[P,K]|T],[[P,M]|TN ]) :- M is K*N, times(N,T,TN). % Finally, diff(X,Y) :- \+ e(X,Y). e(X,X).