• Aucun résultat trouvé

The Graph Coloring Problem

Distributed Constraint Solving

7.2 The Graph Coloring Problem

The graph-coloring problem is another example of a graph-oriented problem, which is often used as an example of constraint solving. Mackworth [1977] notes that many Artificial Intelligence tasks can be formulated as constraint solving problems and solved by backtracking. Agreeing with Sussmann and McDermott’s criticisms of the inclusion of backtracking as a feature in programming languages [1972], he notes that crude backtracking solutions to constraint problems are often inefficient at solving them. Forms of constraint propagation, such as that proposed by Waltz [1975] for the interpretation of line drawings, can drastically cut the search space. Yokoo [1998]

discusses the connection between distributed constraint solving and multi-agent systems.

The k-graph-coloring problem is to find a labeling of the vertices of a graph with labels chosen from a set of k colors, such that no two vertices labeled with the same color are connected by a single edge. The chromatic number of a graph is the minimum value of k such that a k-coloration of the graph can be found. The famous 4-color theorem [Appel and Haken, 1989] is related to this problem. Many practical resource allocation problems are variations of the graph-coloring problem [Chaitin, 1982], [Wood, 1969]. For most graphs, it is in fact easy either to find a k-coloration or to show that no such k-coloration exists [Turner, 1988] although the problem can shown in general to be NP-complete [Gibbons, 1985]. Cheeseman et al. [1991] note that the reason for this seeming contradiction is that graph coloring is an example of a problem where there is only a small distance between examples which are easy to solve and examples which are easy to show insoluble. The really hard problems are those that fall in this band, in the case of graph coloring within a small range of density.

Since solutions are easy to find, brute-force search methods, such as those programmed in Chapter 6, oriented towards problems where it is difficult to find a solution are often not the most appropriate way to solve them. (In other problems, such as chess playing, brute-force search methods continue to outperform others [Hsu et al., 1990]). In some cases, while the problem of finding the optimal solution is NP-complete, acceptable sub-optimal solutions can be found in polynomial time. Korf [1990], for example, finds solutions to sliding-tile puzzles like the 8-puzzle of Chapter 6, which are too large to be found by the branch-and-bound search methods.

Improved solutions can be found by applying modifications to the original

sub-optimal solution [Minton et al., 1990]. The simulated annealing method [Kirkpatrick et al., 1983] is a variant of this.

A concurrent algorithm for finding a k-coloration of a graph, which is particularly suitable for us, was published by Bhandari, Krishna and Siewiork [1988] (henceforth called the BKS algorithm). It is approximate, as it cannot be guaranteed to find a k-coloration if one exists. But in most cases it converges quickly on a solution. It is described in terms of communicating actors representing one vertex of the graph and communicating with other actors representing nearest neighbors. Hence the problem falls into the same family as our all-pairs shortest path algorithm. As there is no concept of direction in edge coloring and the algorithm requires two-way communication between vertices connected by an edge, each edge must be represented by two channels, one for sending messages one way, the other for sending them the other.

The algorithm assumes that the actors representing vertices are each uniquely numbered. Each holds a list of the colors it may choose from, initially of length k, but it may be reduced as coloration of neighboring vertices constrains the possibilities that may be chosen. The algorithm is synchronous. On each cycle each actor selects a color from its list of possibilities and informs the actors representing neighboring nodes of the color chosen. Then any actor labeled i, which has chosen a color not chosen by any of its neighbors labeled j, where j>i, makes the choice permanent, informing its neighbors that it has done so. Following this, all processors delete from their list of possible colors, any of which has been chosen and made permanent by any of their neighbors. The next cycle proceeds with only those actors, which have not made permanent choices. If any actor has the number of colors it can choose from reduced to 0 then the algorithms has failed to find a k-coloration. It must eventually terminate either with a failure or with a k-coloration. This is because on each cycle the actor who is active with the highest index number will always be able to make its choice permanent and so the number of active actors is reduced by at least one on every cycle.

Some elements of negotiation may be observed in this algorithm. Actors may be said to negotiate on colors by making tentative choices and discussing them with their neighbors. There is a “social law” expressing a strict order of precedence on the actors establishing when one must defer to another should both choose the same color.

In GDC the assumption that each actor is on its own processor need not be maintained. A node represents an actor and the mapping of actors to vertices is orthogonal to the abstract description of the algorithm in terms of actors. Although there is no direct synchronization in GDC, the synchronization of the algorithm will arise through the exchange of messages in the system. As messages pass both ways between actors representing vertices connected by an arc, a pair of channels must represent each arc. These will be represented by Cij/Cji being the pair of channels linking the actors representing vertices i and j. The convention will be that the first channel in the pair is used for input, the second for output, the / is just an infix tupling operator. Each actor will store its links to other actors in two lists, one representing arcs linking to lower numbered vertices, the other representing arcs linking to higher

numbered vertices. For example the initial setup for the graph in Figure 7.2.1 (similar to the one used for shortest path problem, but the numbers are vertex labels and the graph is undirected) is:

:- vertex(1,C,[C12/C21,C13/C31,C14/C41,C16/C61,C17/C71],[],S1), vertex(2,C,[C24/C42,C26/C62],[C21/C12],S2),

vertex(3,C,[C34/C43,C35/C53],[C31/C13],S3),

vertex(4,C,[C45/C54,C46/64,C47/C74],[C41/C14,C42/C24,C43/C34],[],S4), vertex(5,C,[C56/C65,C57/C75],[C53/C35,C54/C45],[],S5),

vertex(6,C,[C67/C76],[C61/C16,C62/C26,C64/C46,C65/C56],[],S6), vertex(7,C,[],[C71/C17,C74/C47,C76/C67],S7).

• •

• •

1

2

• 3 4

5

6 7

Fig. 7.2.1 An example graph for the graph coloring problem

Here C is bound to the list of possible colors, while the channel Si is used to return the color eventually chosen for vertex i.

A direct implementation of the BKS algorithm works by having each actor send a message of the form mess(Color,Accepted) on all of its output channels. The channel Color will be bound to the color it has selected from its list of possibilities.

The channel Accepted will be initially unbound, but will later be bound to either true or false depending on whether the color is accepted permanently (which is not known until it has received and analyzed all incoming messages). A test is made on all incoming messages from actors with higher numbered labels and Accepted is bound to true if none of them has the same color as that selected by the actor, false otherwise. If Accepted is bound to true, the actor halts and records the color chosen.

Otherwise it goes through its list of incoming messages again, removing from its list of possible colors any color that has been permanently accepted by any neighbor. The code for this is:

vertex(V,Cols,HiChans,LoChans,Sol) :- select(Cols,Col),

sendCol(Col,Accepted,HiChans), sendCol(Col,Accepted,LoChans), accepted(Col,HiChans,Accepted),

retry(Accepted,V,Col,Cols,HiChans,LoChans,Sol).

sendCol(Col,Accepted,[]).

sendCol(Col,Accepted,[I/O|Chans]) :- O=[mess(Col,Accepted)|Chan],

sendCol(Col,Accepted,Chans).

accepted(Col,[],Accepted) :- Accepted=true.

accepted(MyCol,[[mess(Col,A)|Chan]/O|Chans],Accepted) :- Col=MyCol

| Accepted=false.

accepted(MyCol,[[mess(Col,A)|Chan]/O|Chans],Accepted) :- Col=/=MyCol

| accepted(MyCol,Chans,Accepted).

retry(false,V,Col,Cols,HiChans,LoChans,Solution) :- restrictCols(Cols,HiChans,NewCols1,HiChans1),

restrictCols(NewCols1,LoChans,NewCols,LoChans1), vertex(V,NewCols,HiChans1,LoChans1,Solution).

retry(true,V,Col,Cols,HiChans,LoChans,Solution) :- Solution=node(V,Col).

restrictCols(Cols,[[mess(Col,true)|I]/[Mess|O]|Chans], NewCols,NewChans)

:- removeCol(Col,Cols,NewCols1),

restrictCols(NewCols1,Chans,NewCols,NewChans).

restrictCols(Cols,[[mess(Col,false)|I]/[Mess|O]|Chans], NewCols,NewChans)

:- restrictCols(Cols,Chans,NewCols,NewChans1), NewChans=[I/O|NewChans1].

restrictCols(Cols,[],NewCols,NewChans) :- NewCols=Cols,

NewChans=[].

This will completely implement the BKS algorithm, given the initial vertex setup, needing only code for select to be added. One possibility is always to take the first color from the list, which will lead to a vertex choosing color n from a list of k colors only if it cannot choose any of colors 1 to n–1 due to neighbors having permanently accepting each of them. Note that although there is no central synchronization mechanism, the fact that each actor must read every message from its neighbors before sending out a further message acts to synchronize them.

Although the code given above directly reflects the original BKS algorithm, an inefficiency is apparent. The list of channels from higher numbered vertices on any particular vertex is traversed twice. It is first traversed to find if any of them has chosen the same color as chosen by the vertex in question. It is again traversed in restrictCols to see if any of the colors chosen by higher numbered vertices has been accepted permanently. The list of channels from lower numbered vertices is traversed only in restrictCols. But restrictCols requires the Accepted argument in the messages to be bound, which can only take place when the lower indexed actor has received and read all the messages from its higher indexed neighbors. Thus it is not necessary for two neighboring actors to send messages to each other simultaneously.

The lower indexed actor can wait until it has received a message from the higher and reply by back-communication without affecting the amount of potential parallelism.

This leads to an improved algorithm in which arcs are represented by a single channel. Messages between actors take the form mess(Col,Accepted,Return). Here Col is the color chosen by the higher indexed actor; Accepted indicates whether it has been accepted permanently (as before, it may be unbound at the time the original message is sent) and Return is used for the return communication from the lower indexed actor. Return is set to none if that actor does not make a permanent choice of color in that cycle, or to the color chosen if it does. The initial actor setup for the graph shown previously is:

:- vertex(1,C,[C12,C13,C14,C16,C17],[],S1), vertex(2,C,[C24,C26],[C12],S2),

vertex(3,C,[C34,C35],[C13],S3),

vertex(4,C,[C45,C46,C47],[C14,C24,C34],[],S4), vertex(5,C,[C56,C57],[CC35,CC45],[],S5), vertex(6,C,[C67],[C16,C26,C46,C56],[],S6), vertex(7,C,[],[C17,C47,C67],S7).

where C is the list of possible colors. The revised program (less restrictCol, which remains unchanged) is:

vertex(V,Cols,HiChans,LoChans,Solution) :- select(Cols,Col),

sendCol(Col,Accepted,LoChans), accepted(Col,HiChans,Accepted),

retry(Accepted,V,Col,Cols,HiChans,LoChans,Solution).

sendCol(Col,Accepted,[]).

sendCol(Col,Accepted,[X|Chans])

:- X=[mess(Col,Accepted,YourCol)|Chan], sendCol(Col,Accepted,Chans).

accepted(Col,[],Accepted) :- Accepted=true.

accepted(MyCol,[[mess(Col,A,Ret)|Chan]|Chans],Accepted) :- Col=MyCol |

Accepted=false.

accepted(MyCol,[[mess(Col,A,Ret)|Chan]|Chans],Accepted) :- Col=/=MyCol |

accepted(MyCol,Chans,Accepted).

retry(false,V,Col,Cols,HiChans,LoChans,Solution) :- hiResCols(Cols,HiChans,NewCols1,HiChans1),

loResCols(NewCols1,LoChans,NewCols,LoChans1), vertex(V,NewCols,HiChans1,LoChans1,Solution).

retry(true,V,Col,Cols,HiChans,LoChans,Solution) :- cutoff(Col,HiChans),

Solution=Col(V,Col).

cutoff(Col,[]).

cutoff(Col,[[mess(Col,Accepted,Ret)|Chan]|Chans]) :- Ret=Col,

cutoff(Col,Chans).

hiResCols(Cols,[[mess(Col,true,Ret)|I]|Chans],NewCols,NewChans) :- removeCol(Col,Cols,NewCols1),

hiResCols(NewCols1,Chans,NewCols,NewChans).

hiResCols(Cols,[[mess(Col,false,Ret)|I]|Chans],NewCols,NewChans) :- Ret=none,

hiResCols(Cols,Chans,NewCols,NewChans1), NewChans=[I|NewChans1].

hiResCols(Cols,[],NewCols,NewChans) :- NewCols=Cols,

NewChans=[].

loResCols(Cols,[[mess(MyCol,false,Col)|I]|Chs],NewCols,NewChs) :- Col=/=none |

removeCol(Col,Cols,NewCols1),

loResCols(NewCols1,Chs,NewCols,NewCs).

loResCols(Cols,[[mess(MyCol,false,none)|I]|Chs],NewCols,NewChs) :- loResCols(Cols,Chs,NewCols,NewChs1),

NewChs=[I|NewChs1].

loResCols(Cols,[],NewCols,NewChs) :- NewCols=Cols,

NewChs=[].

Thus, single channels now represents arcs, and carry a stream of messages running from a higher to a lower numbered vertex. Each actor representing a vertex chooses a color from its list of available colors and sends a message to the actors representing its lower-numbered connections only. The message takes the form mess(Col,Accepted,Return). Here, Col is the color chosen, Accept is an unbound channel shared between all the messages to be used to send a further message, but Return is a separate unbound channel for each message sent to be used to receive a reply. The actor then reads the Col argument of the messages it has received from the actors representing its higher-numbered connections. If none of the colors chosen by

its higher-numbered connections are the same as the color it has chosen, it sends a message indicating that it has permanently accepted its color to its lower-numbered connections by binding the previously unbound Accepted to true. Only then, it informs its higher-numbered connections by binding the Return argument in each of the messages it received from them to the color. Otherwise, it indicates that it has not permanently accepted its color by binding the Accepted channel in the messages it previously sent out to false and binding the Return channel in each of the messages it has received to none. If any of the messages it has received has its Accepted channel bound to true, it removes the color in the Col channel of the message from its own list of colors and removes the channel the message was received on from its list of input channels. It also reviews the Return channels in each of the messages it has sent out. If any of them has been bound to a color rather than none it removes that color from its list and removes the channel the message was sent out on from its list of output channels.

As an example of the algorithm in execution, let us consider using it to find a 4-coloration of the graph given in Figure 7.2.1 with initially each vertex having the list red, green, yellow and blue (initialized in the trace below) as possible colors. The selection rule used is that every vertex chooses the first color from its list. Cycles of the algorithm are broken into three stages:

1. Choose colors and inform lower numbered neighbors of choice.

2. Decide whether to make choice permanent depending on messages received from higher numbered neighbors. Inform lower numbered neighbors of permanency of previously communicated choice and higher numbered neighbors of choice or none by back-communication.

3. Receive information on permanent choices and restrict list of colors and channels accordingly.

The trace is:

Cycle 1a

Vertex 1: [r,g,y,b] Chooses r

Vertex 2: [r,g,y,b] Chooses r, informs 1 of choice Vertex 3: [r,g,y,b] Chooses r, informs 1 of choice Vertex 4: [r,g,y,b] Chooses r, informs 1,2,3 of choice Vertex 5: [r,g,y,b] Chooses r, informs 3,4 of choice Vertex 6: [r,g,y,b] Chooses r, informs 1,2,4,5 of choice Vertex 7: [r,g,y,b] Chooses r, informs 1,4,5,6 of choice Cycle 1b

Vertex 1: Receives messages:

2 chose r, 3 chose r, 4 chose r, 6 chose r, 7 chose r Does not make its choice of r permanent

Replies to 2,3,4,6 and 7: no permanent choice made Vertex 2: Receives messages: 4 chose r, 6 chose r

Does not make its choice of r permanent Replies to 4 and 6: no permanent choice made

Further message to 1: choice not permanently accepted

Vertex 3: Receives messages: 4 chose r, 5 chose r Does not make its choice of r permanent Replies to 4 and 5: no permanent choice made

Further message to 1: choice not permanently accepted Vertex 4: Receives messages: 5 chose r, 6 chose r, 7 chose r

Does not make its choice of r permanent

Replies to 5, 6 and 7: no permanent choice made

Further message to 1,2,3: choice not permanently accepted Vertex 5: Receives messages: 6 chose r, 7 chose r

Does not make its choice of r permanent Replies to 6 and 7: no permanent choice made

Further message to 3,4: choice not permanently accepted Vertex 6: Receives message: 7 chose r

Does not make its choice of r permanent Replies to 7: no permanent choice made

Further message to 1,2,4,5 choice not permanently accepted Vertex 7: Receives no messages

Makes its choice of r permanent

Further message to 1,4,5,6: choice made permanent Cycle 1c

Vertex 1: Informed by 2,3,4,6 previous choice not accepted Receives message from 7 of permanent choice of r Closes channel with 7

Restricts color list to [g,y,b]

Vertex 2: Informed by 1 no permanent choice made Informed by 4,6 previous choice not accepted Vertex 3: Informed by 1 no permanent choice made

Informed by 4,5 previous choice not accepted Vertex 4: Informed by 1,2,3 no permanent choice made

Informed by 5,6 previous choice not accepted Receives message from 7 of permanent choice of r Closes channel with 7

Restricts color list to [g,y,b]

Vertex 5: Informed by 3,4 no permanent choice made Informed by 6 previous choice not accepted Receives message from 7 of permanent choice of r Closes channel with 7

Restricts color list to [g,y,b]

Vertex 6: Informed by 1,2,4,5 no permanent choice made Receives message from 7 of permanent choice of r Closes channel with 7

Restricts color list to [g,y,b]

Vertex 7: COLORED r

Cycle 2a

Vertex 1: [g,y,b] Chooses g

Vertex 2: [r,g,y,b] Chooses r, informs 1 of choice Vertex 3: [r,g,y,b] Chooses r, informs 1 of choice Vertex 4: [g,y,b] Chooses g, informs 1,2,3 of choice Vertex 5: [g,y,b] Chooses g, informs 3,4 of choice Vertex 6: [g,y,b] Chooses g, informs 1,2,4,5 of choice Cycle 2b

Vertex 1: Receives messages: 2 chose r, 3 chose r, 4 chose g, 6 chose g

Does not make its choice of g permanent

Replies to 2,3,4 and 6: no permanent choice made Vertex 2: Receives messages: 4 chose g, 6 chose g

Makes its choice of r permanent

Replies to 4 and 6: permanent choice made of r Further message to 1: choice made permanent Vertex 3: Receives messages: 4 chose g, 5 chose g

Makes its choice of r permanent

Replies to 4 and 5: permanent choice made of r Further message to 1: choice made permanent Vertex 4: Receives messages: 5 chose g, 6 chose g

Does not make its choice of g permanent Replies to 5 and 6: no permanent choice made

Further message to 1,2,3: choice not permanently accepted Vertex 5: Receives message: 6 chose g

Does not make its choice of g permanent Replies to 6: no permanent choice made

Further message to 3,4: choice not permanently accepted Vertex 6: Receives no messages

Makes its choice of g permanent

Further message to 1,2,4,5: choice made permanent Cycle 2c

Vertex 1: Receives message from 2 of permanent choice of r Receives message from 3 of permanent choice of r Informed by 4 previous choice not accepted

Receives message from 6 of permanent choice of g Closes channels with 2,3,6

Restricts color list to [y,b]

Vertex 2: COLORED r Vertex 3: COLORED r

Vertex 4: Informed by 1 no permanent choice made Receives message from 2 of permanent choice of r Receives message from 3 of permanent choice of r Informed by 5 previous choice not accepted

Receives message from 6 of permanent choice of g Closes channels with 2,3,6

Restricts color list to [y,b]

Vertex 5: Receives message from 3 of permanent choice of r Informed by 4 no permanent choice made

Receives message from 6 of permanent choice of g Closes channels with 3,6

Restricts color list to [y,b]

Vertex 6: COLORED g Cycle 3a

Vertex 1: [y,b] Chooses y

Vertex 4: [y,b] Chooses y, informs 1 of choice Vertex 5: [y,b] Chooses y, informs 4 of choice Cycle 3b

Vertex 1: Receives message: 4 chose y Does not make its choice of y permanent Vertex 4: Receives message: 5 chose y

Does not make its choice of y permanent Replies to 1: no permanent choice made Vertex 5: Receives no message

Makes its choice of y permanent

Further message to 4: choice made permanent Cycle 3c

Vertex 1: Informed by 4 previous choice not accepted Vertex 4: Informed by 1 no permanent choice made

Receives message from 5 of permanent choice of y Closes channel with 5

Restricts color list to [b]

Vertex 5: COLORED y Cycle 4a

Vertex 1: [y,b] Chooses y

Vertex 4: [b] Chooses b, informs 1 of choice Cycle 4b

Vertex 1: Receives message: 4 chose b Makes its choice of y permanent Vertex 4: Receives no messages

Makes its choice of b permanent

Further message to 1: choice made permanent

Cycle 4c

Vertex 1: COLORED y Vertex 4: COLORED b

Thus the final result, achieved after four cycles is that vertices 2, 3 and 7 are colored red, vertices 1 and 5 are colored yellow, vertex 6 is colored green and vertex 4 is colored blue. Note that the select mechanism used meant that even if more than four colors were available initially, a 4-coloration would have been found since any vertex would only have considered a fifth color had the first four been excluded from it during the course of the algorithm execution.

Now consider how this is represented in GDC. The initial setup is as before, with C bound to [r,g,y,b]. Following the first sending of messages after stage 1a, the situation is:

:- accepted(r,[C12,C13,C14,C16,C17],A1a),

retry(A1a,1,r,[r,g,y,b],[C12,C13,C14,C16,C17],[],S1), C12=[mess(r,A2a,R12a)|C12a],

accepted(r,[C24,C26],A2a),

retry(A2a,2,r,[r,g,y,b],[C24,C26],[C12],S2), C13=[mess(r,A3a,R13a)|C13a],

accepted(r,[C34,C35],A31a),

retry(A3a,3,r,[r,g,y,b],[C34,C35],[C13],S3), C14=[mess(r,A4a,R14a)|C14a],

C24=[mess(r,A4a,R24a)|C24a], C34=[mess(r,A4a,R34a)|C34a], accepted(r,[C45,C46,C47],A4a1),

retry(A4a,4,r,[r,g,y,b],[C45,C46,C47],[C14,C24,C34],[],S4), C35=[mess(r,A5a,R35a)|C35a],

C45=[mess(r,A5a,R45a)|C45a], accepted(r,[C56,C57],A5a),

retry(A5a,5,r,[r,g,y,b],[C56,C57],[C35,C45],[],S5), C16=[mess(r,A6a,R16a)|C16a],

C26=[mess(r,A6a,R26a)|C26a], C46=[mess(r,A6a,R46a)|C46a], C56=[mess(r,A6a,R56a)|C56a], accepted(r,[C67],A6a),

retry(A6a,r,[r,g,y,b],[C67],[C16,C26,C46,C56],[],S6), C17=[mess(r,A7a,R17a)|C17a],

C47=[mess(r,A7a,R47a)|C47a], C67=[mess(r,A7a,R67a)|C67a], accepted(r,[],A7a),

retry(A7a,7,r,[r,g,y,b],[],[C17,C47,C67],S7).

Following this, each accepted actor will bind its final argument to false except accepted(r,[],A7a) which binds A7a to true. Each retry actor, except the one for vertex 7 will then reduce to a hiResCols and a loResCols actor, with the hiResCols actors reducing and sending the return messages which are used in the

loResCols actors. This corresponds to the end of stage 1b and the beginning of 1c, leaving the actor situation:

loResCols actors. This corresponds to the end of stage 1b and the beginning of 1c, leaving the actor situation: