Bounded-wait merge in Shapiro’s Concurrent Prolog

13
New Generation Computing, 2 (1984) 157-169 OHMSHA,LTD. and Springer-Verlag 'Ar OHMSHA, LTD. 1984 Bounded-Wait Merge in Shapiro's Concurrent Prolog Anthony J. KUSALIK Computer Science Department, University of British Columbia, Vancouver, B. C. Canada V6T IW5 Received 9 December 1983 Abstract In A Subset of Concurrent Prolog and Its Interpreter (1983), E.Y. Shapiro introduces the language Concurrent Prolog. In his presentation, the problem of guaranteeing bounded-waiting during a merge operation is used as a programming example. Solutions are proposed for binary and n-ary merges. The solutions are, however, completely dependent on specific operational characteristics of a Concurrent Prolog machine or interpreter. This paper presents an alternate approach in which the property of bounded-waiting is incorporated into the semantics of the programs, demon- strable given only the computational model of the language. The solution strategy is to utilize the familiar systems programming techniques of block- on-input and busy-wait. This approach requires that the language be augmented with a metalogical predicate analogous to the var() predicate of Sequential Prolog. The resultant programs are interesting and illustrative examples of Concurrent Prolog as a programming language. Keywords: Concurrent Prolog, Systems Programming, Bounded-Wait Merge, Logic Programming w 1 Introduction The logic programming language Concurrent Prolog has been the subject of several recent papers. 2'31 The language allows the expression of concurrent computations in logic programs, including the concepts of process creation, communication, synchronization, and termination. It is a successor to the relational language of Clark and Gregory ~) and the language of van Emden and de Lucena. 4) Like them, it supports the data stream programming paradigm. An interpreter for the language, simulating the operation of a Concurrent Prolog

Transcript of Bounded-wait merge in Shapiro’s Concurrent Prolog

New Generation Computing, 2 (1984) 157-169 OHMSHA, LTD. and Springer-Verlag 'Ar

�9 OHMSHA, LTD. 1984

Bounded-Wait Merge in Shapiro's Concurrent Prolog

Anthony J. K U S A L I K Computer Science Department,

University of British Columbia, Vancouver, B. C. Canada V6T IW5

Received 9 December 1983

Abstract In A Subset of Concurrent Prolog and Its Interpreter (1983), E.Y. Shapiro introduces the language Concurrent Prolog. In his presentation, the problem of guaranteeing bounded-waiting during a merge operation is used as a programming example. Solutions are proposed for binary and n-ary merges. The solutions are, however, completely dependent on specific operational characteristics of a Concurrent Prolog machine or interpreter.

This paper presents an alternate approach in which the property of bounded-waiting is incorporated into the semantics of the programs, demon- strable given only the computational model of the language. The solution strategy is to utilize the familiar systems programming techniques of block- on-input and busy-wait. This approach requires that the language be augmented with a metalogical predicate analogous to the v a r ( ) predicate of Sequential Prolog. The resultant programs are interesting and illustrative examples of Concurrent Prolog as a programming language.

Keywords: Concurrent Prolog, Systems Programming, Bounded-Wait Merge, Logic Programming

w 1 Introduction The logic programming language Concurrent Prolog has been the subject

of several recent papers. 2'31 The language allows the expression of concurrent computat ions in logic programs, including the concepts of process creation, communicat ion, synchronization, and termination. It is a successor to the relational language of Clark and Gregory ~) and the language of van Emden and de Lucena. 4) Like them, it supports the data stream programming paradigm. An interpreter for the language, simulating the operation of a Concurrent Prolog

158 A.J. Kusalik

machine, is provided by Shapiro. 2~ This paper assumes the reader is familiar with Concurrent Prolog.

In A Subset o f Concurrent Prolog and Its Interpreter, the task of merging two input streams is considered as a programming example. A program is presented which performs the operation :

merge(EX ] Xs], Ys,EX I Zs~): merge(Xs?, Ys, Zs). (al) merge(Ys,[ Y ] Ys], E Y I Zs] ) :- merge(Xs, Ys?, Zs). -(a2)

merge(Xs,[ 1, Xs). (a3) merge([ 1, Ys, Ys). (a4)

Program (a) : Simple binary merge.

That is, merge(Xs, Ys, Zs) names the relation "Zs is an arbitrary interleaving of the streams (lists) Xs and Ys which preserves the order of the elements." It is indicated that this program does not guarantee bounded-waiting. The problem is manifested as follows. Suppose that when reduction of a goal

merge( lstrml, Istrm2, Ostrm)

is to occur, both input arguments (lstrml and lstrm2) are instantiated. Unifica- tion is possible with the head of either clause (al) or (a2). Which unification succeeds is indeterminate according to the computat ion model of Concurrent Prolog. Operationally it is possible that given any positive integer k, more than k elements of one input stream occur in the output stream between any two elements of the other input stream ; consecutive elements of one stream may not appear in the output for arbitrarily long periods of time.

To solve this problem, clauses (a l ) and (a2) are replaced by :

merge( E X ] Xs l , Ys, E X I Zs ] ) :- rnerge ( Ys, Xs ?, Zs ). (al ' ) merge(Xs, [ Y I Ys], [ Y ] Zs] ) : - merge( Ys?, Xs, Zs). (a2')

It is claimed that the program, as modified, achieves bounded-wait ing given appropriate characteristics of a Concurrent Prolog machine. The required property is described as follows :

"Assume that the clauses in the program are ordered (say, by text order), and assume that a process A has several clauses Ai, : Bi , I ~ i < n, with empty guard whose head unifies with a process A, at the time A is created. We say that a Concurrent Prolog machine (interpreter) is stable if it always uses the first clause A~: B~ to reduce A. A Concurrent Prolog machine for which this condition holds if the number of steps required to unify A with A~ is less than or equal to those required to unify A with Ai, for l<i<_n, is called weakly stable. Note that a stable machine is also weakly stable." (See Ref. 2), pg. 22).

This property imposes an operational priority on each clause, based on its position in a program. This, in turn, can be used to attribute relative priorities to input streams. Given a stable machine then, the modified merge program achieves bounded-wait ing by lowering the priority of the stream from which an

Bounded-Wait Merge in Shapiro's Concurrent Prolog 159

element was most recently removed. This approach is extended by Shapiro to n-ary merge. Two possible

program formulations are presented. One is termed a type of round-robin stream-scheduler. Its i th recursive clause is

m e r g e ( X , , X : . . . . . I X ~b Xi~ ..... X , , EX I Z s ~ ) : - m e r g e ( X : , X ~ . . . . . X i ? ..... X ,, X l, Zs ).

In the other, the priority of the stream that is read is decreased, it has the i th recursive clause

m e r g e ( X , , ..., EX ] Xi~ .. . . . X , , ~X [ Z s l ) :-

merge(X1 .. . . . X i -~ , Xi+t . . . . . X , , X i ? , Zs) .

Shapiro's solution to the bounded-wait merge problem requires that a Concurrent Prolog machine (or interpreter) be weakly stable, or weakly stable with high probability. However, such a machine need not have this proper ty- - it is not impossible to eliminate or prevent. The programs above may therefore not demonstrate bounded-wait ing given an arbitrary Concurrent Prolog machine.

It should be possible to specify the concept of bounded-wait ing directly within the semantics of a Concurrent Prolog program. The prescribed program behavior should be demonstrable given the computat ional model of the lan- guage. The remainder of this paper is directed toward development of such programs, first for binary, and then for n-ary merge.

w A Different Approach The initial step in the development of an alternative approach is the

determination of a computat ional strategy. The following seems to be reason- able and sufficient :

A binary merge process waits for input on either of its two input streams. When an element is present it is read and placed on the output stream. The other input stream is then checked for any input. If an element is present, it is read and placed on the output stream, The process then reverts to waiting for more input on either stream.

This is a combinat ion of the familiar systems programming concepts of block- on-input and busy-wait. To perform a busy-wait operation, a program must be able to test whether a variable is instantiated. This requires the addit ion to Concurrent Prolog of a metalanguage predicate, varbl( _ ), which behaves just as the Sequential Prolog predicate v a r ( ) , with the exception that it ignores read- only annotations, varbl( ) is thus or thogonal to the Concurrent Prolog metalanguage predicate w a i t ( ) . Reduction of wait suspends until (the princi- ple functor of) its argument is instantiated, at which time it reduces to true.

varbl never suspends and reduces to true if, and only if, its argument is a variable.

160 A.J. Kusalik

2.1 Binary Merge The following program accomplishes the merge of two input streams

using this strategy.

merge(block, ~E I Strml], Strm2, ~E I Mrg]) :- (bl) merge(busywait, Strm2, Strml ?, Mrg).

merge(block, Strml, EEI Strm2], ~ E I Mrg]) :- (b21 merge(busy wait, Strml, Strm2 ?, Mrg).

merge(block, Strml, ~ ], Strml). (b3) merge(block, ~ J, Strm2, Strm2). (b4)

merge(busywait, E E Ir PriorityStrmJ, HoldStrm, E E I Mrg] ) :- (b5) merge(block, PriorityStrm ?, Holdstrm, Mrg).

merge( busv wait, ~ ], HoldS trm, HoldS trm ). ( b6 ) merge( busywait , PriorityStrrn, HoldStrm, Mrg ) :- (b7)

varbl( PriorityStrm) I merge(block, PriorityStrm, HoldStrm~ Mrg).

merge(Strml, Strm2, MrgStrm) :- merge(block, Strm l, Strm2, MrgStrm). (bS)

Program (b): Bounded-wait binary merge.

The following is an example of a computat ion of the merge process. In this, and subsequent discussions, let the symbol " - - ' " indicate process reduction, and let

p - - ( x ) - ~ q

denote that "process p reduces to system q using clause (x)". Consider the system

produce C(CO), produceD(DO), merge(CO ?, DO ?, Out)

The initial reduction is

merge(CO ?, DO ?, Out)--(b8)-~ merge(block, CO ?, DO ?, Out)

Assuming that no input is yet present on streams C and D, reduction suspends because of the read-only annotations, After a time the produceC process in- stantiates CO to Ecl Ii CI] (outputs the term el). The merge process can resume, generating cl as output :

merge(block, ~ct l C1] ?, DO?, ~c~ l Out l]) - - (bl )~, merge(busywai t , DO ?, C1 ?, Outl)

The process must now check for input on stream D (the busy-wait operation). There is no input, as DO is uninstantiated. Reduction via clauses (b5) and (b6) suspends. It is not intended that program execution suspend in such a case; hence the presence of clause (b7). The guard

varbl(DO ?)

Bounded-Wait Merge in Shapiro's Concurrent Prolog 161

reduces to true, allowing

merge(busy wait, DO ?, C1 ?, Outl) - - (b7)~ merge(block, DO ?, C1 ?, Outl)

The merge process returns to waiting for more input. Assume that concurrent with the last process reduction (but following the "commit"), produceC outputs the term c2 and produced outputs d. Reduction can occur using either of the two .clauses (b l) or (b2). According to the computational model, one of the alternatives is non-deterministically chosen and the other is abandoned. Assume that process reduction occurs using (b2) and c2 is placed in the output stream :

merge(block, [d [ D1] ?, ~c2 ] C2] ?, Ec2 ] Out2])--(b2) --~ merge(busy_wait, Ed ] D1] ?, C2 ?, Out2)

This time, during the busy-wait state of the merge, input is found, so the next reduction is

merge(busy_wait, E d I DI] ?, C2 ?, I d Out31)--(b5)~ merge(block, D1 ?, C2 ?, Out3)

Finally, suppose that produceC and produceD terminate, mstantiating C2 and D1 to the empty list. The merge process terminates via (b3) or (b4). The result of the entire computat ion is that Out is instantiated to Ect,e2,d~ .

This example demonstrates how the merge process achieves bounded- waiting. Clause (bl) and (b2) cause execution to be suspended while there is no input. The effect of clauses (b5) and (b7) is the reading of an element, if one exists, from the stream not read as a consequence of the previous reduction. This operation is realized given any Concurrent Prolog machine, including one with the property of stability.

By convention, end-of-stream is indicated by the empty list, [ J . Axioms (b3) and (b4) handle the occurrence of end-of-stream during the blocked state by terminating the process and unifying the remaining input stream and the output stream. Similar action is taken during busy-waiting (clause (b6)). Clauses (b4) and (b6) can be replaced by the single axiom

merge( , ~ 7, Strm, Strm). (b4')

to make the program more concise. An alternative formulation of the merge program is:

merge([E ] StrmlJ, Strm2, [E t~ MrgT): busy waR(Strm2, Mrg, NewStrm2, NewMrg) l merge( Strml ?, NewStrm2, NewMrg).

merge(Strml, rE ] Strm21, EE] MrgJ):- busy_wait(Strml, Mrg, NewStrml, NewMrg) I merge( NewStrml, Strm2 ?, NewMrg).

merge( Strml, E 7, Strml). merge(E ], Strm2, Strm2).

162 A.J. Kusalik

busy wait(UE I Strml, [E I Mrgl, Strm ?, Mrg). busy wait( U 1, Mrg, ~ 1, Mrg). busy wa#(Strm, Mrg, Strm, Mrg) : varbl(Strm) l true.

Program (c) : Alternative bounded-wait binary merge.

This formulation uses the same approach, except that the busy-wait operation, the check for other input, is accomplished by solution of a guard of the f•rm

busy wait(Strm, Mrg, NewStrm, NewMrg).

The operational semantics of the reduction of such a goal are as follows. The input stream bound to Strm is checked for input. Any input other than the empty list is placed on the output stream, Mrg. No action is taken on end-of- stream except to pass on the indication. On successsful reduction the variables NewStrm and NewMrg are bound to the remainder of the input and output streams, respectively.

A priority-based merge of two input streams is an obvious extension of programs (b) and (c):

priority merge([E I PriorityStrml, NormalStrm, [E I Mrgl) : priority merge(PriorityStrm ?, NormalStrm, Mrg).

Priority merge(PriorityStrm, [ E I NormalStrml, [ E I Mrg]) :- varbl( PriorityStrm) l priority merge(PriorityStrm, NormalStrm ?, Mrg).

priority merge( ~ 1, NormalStrm, NormalStrm). priority merge( PriorityStrm, [ 1, PriorityStrm ).

Program (d) : Priority-based binary merge.

In this program, input is taken from the "normal" stream only if none is present on the "priori ty" stream, as determined by the success of the guard

varbl(PriorityStrm).

2 . 2 n-ary Merge It is always possible to merge n streams by constructing a balanced binary

tree of binary merge processes. Such a tree has depth ~log2n] and n-1 merge nodes. For example, if n is 4, the following could be used :

merge(Strml, Strm2, Strm3, Strm4, MrgAll) :- merge( Strml, Strm2, Mrg12), merge( Strm3, Strm4, Mrg34), merge( Mrgl2, Mrg34, MrgAll).

If each binary merge exhibits bounded-waiting, the resulting n-ary merge achieves bounded-waiting. This approach, however, does not facilitate easy, dynamic addition or deletion of streams to a system at runtime. The maximum possible number of streams must be known in advance, and clauses must be

Bounded-Wait Merge in Shapiro's Concurrent Prolog 163

written to accommodate all potential intermediate values. It is preferable to have the necessary tree dynamically constructed by a predicate of the form

merge(StrmList, Mrg),

where StrmList is an arbitrary list of (any number of) streams and Mrg is the resulting output stream.

merge( [ Strm], Strm). merge([ ], [ ] ). merge( StrmList, Mrg) :-

dif ( StrmList, [ ~ ), di f ( StrmList, [ _] ), halve( StrmList, Halfl, Half2) l merge( Halfl, Mrgl), merge( Half2, Mrg2), merge(Mrgl ?, Mrg2 ?, Mrg).

halve([ Strml, Strm211StrmListl, [ Strml li Halfl], [Strm211Half2]) :- halve( StrmList, Half1, Half2).

halve([ ], ~ ], [ 1). halve( [ SingleStrm], [ SingleStrm], [ ] ).

Program (e): n-ary merge.

Program (e) creates n - 1 merge processes interconnected by a communication network which forms a binary tree. The tree is balanced, having depth [logznl. Using this program, the goal

merge([Strml ?, Strm2 ?, Strm3 ?, Strm4 ?], Mrg)

reduces to the system

merge(Strml ?, Strm3 ?, Mrgl), merge(Strm2 ?, Strm4 ?, Mrg2), merge(Mrgl ?, Mrg2 ?, Mrg)

Again, such an n-ary merge computation demonstrates bounded-waiting if the binary merge processes have this property.

It is possible to have a single, complete n-ary merge process that achieves bounded-waiting. This is demonstrated in program (f).

merge(block, StrmList, , Mrg) : (fl) wait strm(StrmList, A ctiveStrm, CheckStrms) ] merge( arrival, A ctiveStrm, CheckStrms, Mrg).

merge(block, [ ] , , [ ] ). (f2)

merge(arrival, [ E i ActiveStrm], CheckStrms, [E i Mrg]) :- (f3) merge(busy_ wait, CheckStrms, [ ActiveStrm ?1, Mrg).

merge( arrival, [ 1, CheckStrms, Mrg ) :- (f4) merge(busy_ wait, CheckStrms, [ 1, Mrg).

merge(busywait, [[E', Strm] I CheckStrms], CheckedStrms, [El Mrg]): (1"5)

164 A.J. Kusalik

merge(busy wait, CheckStrms, L Strm ? Ii CheckedStrms], Mrg). merge(busy_ wait, [ E ] I CheckStrrns ], CheckedStrms, Mrg ) :- (f6)

merge(busy_ wait, CheckStrms, CheckedStrms, Mrg ). merge(busy_ wait, E Strm I CheckStrms], CheckedStrms, Mrg) : (f7)

varbl( Strm) I merge(busy_ wait, CheckStrms, I Strm I CheckedStrms], Mrg).

merge(busy_ wait, [ ], CheckedStrms, Mrg ) :~ (PS) merge(block, CheckedStrms, , Mrg ).

wait strm([[El Strm] l StrmList], EEl Strm], StrmList). (f9) wait strm(~[ ~ I StrmList], ~ 1, StrmList). (fl0) wait strm(~Strm I StrmList], ActiveStrm, [ Strm I CheckStrms] ) :- (ill)

varbl ( Strm), wait_ strm ( StrmList, A ctiveStrm, CheckStrms ) I true.

merge(StrmList, Mrg) :- merge(block, StrmList, , Mrg). (f12) Program (f): Bounded-wait n-ary merge.

The program strategy is again to utilize the concepts of block-on-input and busy-wait. Axiom (f12) initiates the merge process. Solution of the guard of clause (fl) constitutes the blocked-on-input state of the process. In the attempt to solve

w a i t strm(StrmList, A ctiveStrm, CheckStrms),

an OR-parallel tree of reduction alternatives is formed. Each is suspended, awaiting input. When input occurs, the OR-tree collapses and the guard is satisfied with ActiveStrm being bound to the stream having the input and CheckStrms being instantiated to the list of all other streams. The program uses clauses (f3) and (f4) to appropriately handle the input--ei ther placing the term in the output stream or, if end-of-stream, removing the stream from'further computa- tions. In the busy-wait state, all streams other than the active one are checked for input by clauses (f5), (f6), and (f7). Axiom (f8) diagnoses that all streams have been checked and causes the process to revert back to its blocked-on-input state. Finally, (f2) handles the case that end-of-stream has been encountered on all input streams and terminates the process.

The wait strm portion of the program demonstrates an interesting programming capability of Concurrent Prolog " the construction of an OR-tree of parallel suspended reductions. Each is suspended awaiting input due to read- only annotations of variables. When input occurs, the tree collapses, domino- like, due to execution of the commit operator and process abandonment. Consider as an example the goal

merge(block, EStrml ?, Strm2 ?, Strm3 ?,_ , Mrg)

where each input variable is uninstantiated. Only clause (fl) can be used for reduction, recursively invoking the goal in the guard

Bounded-Wait Merge in Shapiro's Concurrent Prolog 165

wait_strm(IStrrnl ?, Strm2 ?, Strm3 ?],ActiveStrm, CheckStrms) (a)

as a new system. Clauses (f9), (riO), and (f! 1) are all potential candidates for reduction. However, unification with the head of (f9) and (fl0) suspends due to read-only annotations. Unification with ( f l l ) can proceed, invoking the guard system

varbl(Strml ?), wait strm( [Strm2 ?, Strm3 ?1, ActiveStrm, CheckStrmsl)

(8) The first goal solves immediately. The recursive solution of the second goal is analogous to the case above - - three OR-parallel reduction attempts are initiat- ed. Two suspend at unification with clauses (f9) and (fl0). The third, unifying with the head of (fl 1), invokes the guard system

varbl(Strm2 ?), wait strm([Strm3 ?], A ctiveStrm, CheckStrms2) Again the first goal solves immediately and three OR-parallel alternatives are created. One using clause (fl 1), invokes the guard system

varbl(Strm3 ?), w a i t strm([ ], A ctiveStrm, CheckStrms3)

The first goal of this system reduces to true. But the second fails. At this point there exists a tree of suspended OR-parallel reduction attempts as depicted in Fig. 1. Reduction is suspended until a unification with the head of either clause (f9) or (fl0) succeeds. This cannot occur until input occurs.

<guard invocation',' wait_ strm ( [ Strm l Z Strrn2?, Strm3? l , A ctiveStrm, CheckStrms )

I ( f 1 1 ) I ( f l O ) i I

I (suspended)

<guard invocations

I i(f9) I

(suspended)

wait_ strm( [ Strm2?, Slrm3?], ActiveStrm, CheckStrms2) I [

(fll) I (flO) I(f9) [ r

(suspended)* (suspended)

<guard invocationS* merge( [ Strm3?], ActiveStrm, CheckStrms3)

i I ~ (f]o) I (f9) I

(suspended)* * (suspended)* *

Fig. 1 OR-parallel tree of suspended reductions.

166 A.J. Kusalik

Suppose that Strm2 becomes instantiated to Ea I Strm2'l. The following reduction is now poss ib le '

wait strm(EEal Strm2'] ?, Strm3 ?], Ea I Strm2"l, IStrm3 ?]) -(t9) --, true (/3')

This causes abandonment of the two OR-parallel alternatives marked * in the diagram. In turn, the descendant alternatives marked ** are abandoned. With the system (/3) reduced to true, the reduction"

wait strm([Strml ?,[a I Strm2'] ?, Strm3 ?], [a I Strm2'], [Strml ?, Strm3 ?]) - - ( f l 1)-~" true (a')

succeeds and the last two OR-parallel alternatives are abandoned. The guard (or) being solved, the original merge process can now continue via

merge(block, E Strml ?,Ea l Strm2"], Strm3 ?],_, Mrg)--( f l )~ merge (arrival, Ea I Strm2"], [Strml ?, Strm3 ?], Mrg).

Note that if input is present on one of the streams upon the initial invocation of the goal (a) , the entire OR-tree is not constructed" one of the unifications with the head of clauses (19) or (fl0) succeeds immediately.

An alternative formulat ion of the n-ary merge program is as follows.

merge( StrmList, [ E I Mrg] ) : (gl)

wait_strm( StrmList, [ E I Strm], CheckList), busywait(CheckList ?, Mrg, NewStrmList, NewMrg) I merge(~Strm ?I NewStrmList], NewMrg).

merge( StrmList, Mrg ) :- (g2)

wait strm(StrmList, E ], CheckList), busy_wait(CheckList ?, Mrg, NewStrmList, NewMrg) l merge( NewStrmList, NewMrg ).

merge([ ], [ ]). (g3)

busy wait(E[EIStrm] ] CheckList], [ E ~p Mrg], [Strm ? I XewStrmList], NewMrg): (84) busy wait(CheckList, Mrg, NewStrmList, NewMrg).

b u s y wait([ ~ ] I CheckList], Mrg, NewStrmList, NewMrg) : (g5)

busy_wait(CheckList, Mrg, NewStrmList, NewMrg). busy_ wait([Strm I CheckList], Mrg, [Strm I NewStrmList], NewMrg) :- (g6)

varbl( Strm) I busywait(CheckList, Mrg, NewStrmList, NewMrg).

busywait([ ], Mrg, [ ], Mrg). (g7)

Program (g):! Alternative bounded-wait n-ary merge.

The specification of wait strm is as before. In this formulation more OR- parallel alternatives are created when waiting for input, since (gl) invokes a wait strm guard expecting a non-empty list structure, while (g2) invokes another expecting an end-of-stream indication. The read-only annotat ion of the variable CheckList prevents reduction of the busywait goal until the wait strm

Bounded-Wait Merge in Shapiro's Concurrent Prolog 167

goal has succeeded (and, hence, input has been found). Program (g) has the property that if at least one element is available on each of m input streams, only one recursive process reduction is necessary for the m first elements to appear in the output stream.

2 . 3 Observat ions on n-ary Merge Programs Consider the solution of

m e r g e ( [ S t r m l ?, S t rm2 ?, S t rm3 ?, S t rm4 ?1, MrgAl l )

using either program (e) or program (g). In the former case a tree of binary merge processes is created as represented in Fig. 2.

Strrnl Strm3 Strm2 Slrm4 \ / \ / Mrgl3 Mrg24

\ / MrgA ll

Fig. 2

When input arrives, say on stream Strm4, three process reductions occur yielding the system depicted in Fig. 3.

Strml Strm3 Strm2 Strm4' \ / \ / Mrg 13 Mrg 24'

\ / MrgA ll'

Fig. 3

Only three processes changed state. In general the number of processes undergo- ing transition is minimal, especially in cases of large values of n. With program (g) the entire tree of OR-parallel alternatives is collapsed when input appears, only to be reconstructed when the process reverts to its blocked-on-input state. This results in a great deal of interpreter overhead. Consequently programs (f) and (g) are much slower than program (e) when executing under Shapiro's Concurrent Prolog interpreter. 2)

It is interesting that program (e) provides n-ary merge by constructing a tree of AND-parallel processes, while programs (f) and (g) utilize a tree of OR- parallel suspended alternatives. In the first case the tree is defined by com- munication channels and changes in structure occur only on end-of-s tream. With the latter two programs the tree is defined by reduction alternative and is repeatedly reconstructed as a computation proceeds.

168 A.J. Kusalik

w Implementation All the programs introduced were developed and tested on a version of

Shapiro's Concurrent Prolog interpreter modified by the author to run under Edinburgh UNIX t Prolog, Version NU7 on a PDP-11/23. The metalogical system predicate varbl(_) was added to the language by the addition of the following simple Sequential Prolog clauses to the interpreter:

varbl(X) :- vat(X), !. varbl(X ?) :- varbl(X). system( varbl ( _) ).

w Conclusions An alternative has been given to Shapiro's solution of the bounded-wait

merge problem in Concurrent Prolog. The approach incorporates the idea of bounded-waiting directly into the semantics of the programs. This is accom- plished by use of the familiar programming concepts of block-on-input and busy- wait. Generalized n-ary bounded wait merge is attained via two different approaches. One creates a binary tree of binary merge processes. The other utilizes the power of the commit operator and OR-parallelism to accomplish the merge by a single process. The programs can demonstrate bounded-waiting given any Concurrent Prolog machine, not just one having the property of stability.

The solution does require the addition of a metalogical predicate varbl(_) to Concurrent Prolog. This predicate is analogous to Sequential Prolog's var(_), with the additional property that it ignores read-only annota- tions.With this new predicate, programs can easily be written which perform busy-wait operations or which suspend awaiting input on arbitrarily many streams. Therefore, varbl(_) appears to be a useful and justifiable addition to Concurrent Prolog.

Acknowledgements I would like to thank Harvey D. Abramson of the University of British

Columbia for his suggestions and encouragement. My work in this area is made possible in part by scholarship funding of the NSERC.

References I) Clark, K.L. and Gregory, S. : " A Relational Language for Parallel Processing,"

Proceedings of the ACM Conference on Functional Programming Languages and Computer Architectures (ACM, Portsmouth, October 1981) 17 I- 178.

2) Shapiro, E. Y. : "A Subset of Concurrent Prolog and Its Interpreter," ICOT Technical

t UNIX is a trademark of Bell Laboratories.

Bounded-Wait Merge in Shapiro's Concurrent Prolog 169

Report, TR-O03 (ICOT, Tokyo, January 1983). 3) Shapiro, E.Y. and Takeuchi, A.:"Object Oriented Programming in Concurrent

Prolog,'" New Generation Computing 1, No. 1 (OHMSHA, LTD. and Springer-Verlag, 1983) 25 48.

4) van Emden, M. H. and de Lucena, G. J. : "Predicate Logic as a Programming Language for Parallel Programming," Logic Programming (ed. K. L. Clark and S.-~,. T~rnlund) (Academic Press, London, 1982) 189 198.