This page was automatically generated by NetLogo 5.0.4.
The applet requires Java 5 or higher. Java must be enabled in your browser settings. Mac users must have Mac OS X 10.4 or higher. Windows and Linux users may obtain the latest Java from Oracle's Java site.
In order for this to work, this file, your model file (ADOPTgc.nlogo), and the files NetLogoLite.jar and NetLogoLite.jar.pack.gz must all be in the same directory. (You can copy NetLogoLite.jar and NetLogoLite.jar.pack.gz from the directory where you installed NetLogo.)
On some systems, you can test the applet locally on your computer before uploading it to a web server. It doesn't work on all systems, though, so if it doesn't work from your hard drive, please try uploading it to a web server.
You don't need to include everything in this file in your page. If you want, you can just take the HTML code beginning with <applet> and ending with </applet>, and paste it into any HTML file you want. It's even OK to put multiple <applet> tags on a single page.
If the NetLogoLite files and your model are in different directories, you must modify the archive= and value= lines in the HTML code to point to their actual locations. (For example, if you have multiple applets in different directories on the same web server, you may want to put a single copy of the NetLogoLite files in one central place and change the archive= lines of all the HTML files to point to that one central copy. This will save disk space for you and download time for your users.)
powered by NetLogo
view/download model file: ADOPTgc.nlogo
Title: Graph Coloring using Adopt
Author: Jose M Vidal and Ionel Muscalagiu
Description:
We solve the graph coloring problem using the
Adopt algorithm from
The tree is rooted at the top of the screen. All the lines between nodes
represent constraints. The light-colored lines (cyan) are also the parent-child
links on the tree. The color of the node is, well, the current color of the node.
The numbers on each node represent the LB-threshold-UB:ID.
;Graph coloring using distributed algorithms ;Uses Adopt, from AAMAS03 ;by Jose Vidal and Ionel Muscalagiu breed [ nodes ] breed [ context-agents ] ;edges is a list of lists: a 2D array indexed by who. The value is 1 if there is a link, 0 otherwise. ;num-colors ;domain is the list of allowed colors globals [edges domain time tot-edges ] ;parent is the 'who' of the parent ;parent-agent is the actual parent ;children is a list of the 'who' of the children ;children-agent is an agentset of the children ;level in the tree. root is 0 ;descendant-neighbors is a list of the 'who' of all nodes that are descendants and have a constraint with me ;neighbors-list is a list of the 'who' of all nodes that have a constraint with me ;dfs-neighbors is like above but might include others, it is used by the dfs-tree algorithm of Modi. ;threshold- as in paper ;current-context is CurrentContext from the paper ;lbounds is lb(d_i,x_l) ;ubounds is ub(d_i,x_l) ;t ;context is context(d_i,x_l) ;terminate is set to true if received a terminate message ;dead is set to true if vertice has terminated execution ;d_i from the paper is represented by 'color' ;last-threshold-message is a list indexed by who were each item is the last threshold msg sent to that agent. [val current-context] nodes-own [message-queue parent parent-agent children children-agent level descendant-neighbors neighbors-list dfs-neighbors dfs-change threshold current-context lbounds ubounds t context terminate dead messages-handled messages-received last-threshold-message context-display need-to-backtrack AgentC_Cost the-links] ;returns a list of legnth n where each item is v to-report make-list [n v] let res 0 set res [] repeat n [ set res fput v res] report res end to-report lists-equal? [l1 l2] let i 0 if (length l1 != length l2) [report false] set i 0 while [i < length l1][ if (item i l1 != item i l2)[report false] set i i + 1 ] report true end to make-link [v1 v2] let tmp 0 if (v2 < v1)[ set tmp v2 set v2 v1 set v1 tmp] if (not neighbors? v1 v2) [ set edges replace-item v1 edges (lput v2 (item v1 edges)) ] end to-report neighbors? [v1 v2] let tmp 0 if (v2 < v1) [ set tmp v2 set v2 v1 set v1 tmp] report member? v2 (item v1 edges) end ;reports true if edges and num-nodes represent a connected graph to-report connected? let clique 0 let i 0 let j 0 set i 0 set clique [] set clique lput i clique set i 1 set j 0 while [j < num-nodes][ while [i < num-nodes][ if (not member? i clique)[ if (not empty? filter [neighbors? ? i] clique)[ set clique lput i clique if (length clique = num-nodes)[ report true ] ] ] set i i + 1 ] set j j + i ] report false end to-report subgraph [n] ; report the complete connected subgraph containing n1 let stack 0 let graph 0 let nr 0 let ag 0 let vec 0 set graph (list turtle n) set stack (list n) while [length stack > 0] [ set ag first stack foreach [the-links] of turtle ag[ if not member? turtle ? graph [ set graph lput turtle ? graph set stack lput ? stack ] ] set stack but-first stack ] report graph end ;sets 'edges' and 'neighbors-list' to make-random-edges let edges-created 0 let t1 0 let t2 0 let v1 0 let v2 0 let tmp 0 let g 0 ask nodes [ set neighbors-list [] ] set edges make-list num-nodes [] set edges-created 0 set g (list turtle 1) while [length g < num-nodes] [ set t1 one-of nodes with [not member? self g] ask t1 [set v1 who ] set t2 item random length g g ask t2 [set v2 who ] if (v1 != v2 and (not neighbors? v1 v2)) [make-link v1 v2 ask t1 [set the-links lput v2 the-links] ask t2 [set the-links lput v1 the-links] set edges-created (edges-created + 1) ] set g subgraph 1 ;show g ] while [edges-created < tot-edges] [ set t1 one-of nodes ask t1 [set v1 who ] set t2 one-of nodes with [self != t1 and not member? t1 the-links] ask t2 [set v2 who ] if v2 != nobody [make-link v1 v2 set edges-created (edges-created + 1)] ] set v1 0 while [v1 < num-nodes][ set tmp (item v1 edges) ask turtle v1 [ set neighbors-list [] ] set v2 0 while [v2 < num-nodes][ if (neighbors? v1 v2)[ ask turtle v1 [ set neighbors-list lput v2 neighbors-list ] ] set v2 v2 + 1 ] set v1 v1 + 1 ] end to set-level ifelse (parent = -1)[ set level 0 ][ set level ([level] of parent-agent) + 1 ] end ;vertice function to find-best-position let possible-patches 0 let siblings 0 let best-patch 0 ifelse (parent = -1) [ set xcor 0 ][ set siblings nodes with [self != myself and (level = [level] of myself or who = [parent] of myself)] set possible-patches patches with [distance-nowrap myself < 20 and (pycor = round [ycor] of myself)] set best-patch max-one-of possible-patches [sum [log (distance-nowrap myself + .1) 2] of siblings] set xcor ([pxcor] of best-patch) if (xcor < 0 + min-pxcor + 50) [set xcor 0 + min-pxcor + 50] if (xcor > max-pxcor - 10) [set xcor max-pxcor - 10] ] end ;nodes function. Draws an edge from this vertice to other-vertice to draw-edge [other-vertice col] let dista 0 let oc 0 let ox 0 let oy 0 set oc color set ox xcor set oy ycor set color col set dista distance-nowrap other-vertice set heading towards-nowrap other-vertice pen-down fd dista pen-up set color oc setxy ox oy set heading 0 end to draw-edges let v1 0 set v1 0 while [v1 < num-nodes][ no-display ask (turtle v1) [ without-interruption [ foreach neighbors-list [ draw-edge (turtle ?) blue ] ] ] display set v1 v1 + 1 ] ;color tree differently no-display ask nodes [ if (parent >= 0)[ draw-edge parent-agent cyan ] ] display end to setup-turtles let i 0 ;set num-colors 3 set domain [] set time 1 set tot-edges min list round (num-nodes * edge-density) ((num-nodes ^ 2 - num-nodes) / 2) set i 0 while [i < num-colors][ set domain lput item i [15 105 64 125 45 85 35 55 5] domain set i i + 1 ] ;show num-nodes create-nodes num-nodes [ set size 30 set shape "circle" set label who set parent -2 set terminate false set dead false set lbounds make-map set ubounds make-map set t make-map set context make-map set the-links [] if (who != 0)[ set-current-plot "Messages" create-temporary-plot-pen (word who) set-plot-pen-color (5 + 10 * who) mod 140 set-current-plot "Message-queue" create-temporary-plot-pen (word who) set-plot-pen-color (5 + 10 * who) mod 140 ] ; set color item (random-int-or-float num-colors) domain set color item 0 domain set messages-handled 0 ] end to setup let i 0 clear-output clear-all show "Setup" setup-turtles ;make-edges make-random-edges set-dfs-tree repeat num-nodes [ ask nodes [ set-level ] ] ;If there is only one root (level =0) then we have a tree. if (not (count (nodes with [level = 0]) = 1))[ show "ERROR: more than 1 root...."] set i max [level] of nodes ;show i ask nodes [ ifelse ( level != i ) [ set ycor (max-pycor - 20) - (level * ((world-height - 30) / i))] [ set ycor (max-pycor - 10) - (level * ((world-height - 30) / i))] ] repeat 12 [ ask nodes [ find-best-position ] ] draw-edges ;;set up the context display create-context-agents num-nodes * num-nodes [ set size 8 set shape "circle" set color black ] ask nodes [ set context-display context-agents with [who >= (([who] of myself + 1) * num-nodes) and who < (([who] of myself) + 2) * num-nodes] ] set i 0 while [i < num-nodes][ ask ([context-display] of turtle i) [ set ycor ([ycor] of turtle i) + 15 set xcor ([xcor] of turtle i) - (5 * num-nodes) + 10 * (who - ((i + 1) * num-nodes)) set label(who - ((i + 1) * num-nodes)) ] set i i + 1 ] end to setup-ADOPT ;;adopt::initialize ask nodes [ set messages-received 0 set AgentC_Cost 0 initialize] show "All initialized" ;reset-ticks end to update-contexts let i 0 let c 0 set i 0 while [i < num-nodes][ ask ([context-display] of turtle i)[ set c item (who - (i + 1) * num-nodes) [current-context] of turtle i ifelse (c = -1) [ set color black ][ set color c ] ] set i i + 1 ] end to go let done 0 set time time + 1 if (show-messages) [print "===================="] ask nodes [ handle-message set label (word LB "-" threshold "-" UB ":" who) set-current-plot "Messages" set-current-plot-pen (word who) plot messages-received] update-contexts ask nodes [ if (need-to-backtrack) [backtrack] set-current-plot "Message-queue" set-current-plot-pen (word who) plot length message-queue ] set done reduce [?1 and ?2] [dead] of nodes type time type "- " ask nodes [ type position color domain ] if (done) [stop] end to go-cycle let done 0 if (show-messages) [print "===================="] set time time + 1 ask nodes [ set need-to-backtrack false set message-queue lput list "cycle" "done" message-queue] set done (reduce [?1 and ?2] [dead or empty? message-queue or first first message-queue = "cycle"] of nodes) while [not done][ ask nodes [ handle-message set label (word LB "-" threshold "-" UB ":" who) set-current-plot "Messages" set-current-plot-pen (word who) plot messages-received] set done (reduce [?1 and ?2] [dead or empty? message-queue or first first message-queue = "cycle"] of nodes) update-contexts ] ask nodes [ if (not empty? message-queue and first first message-queue = "cycle") [ set message-queue butfirst message-queue ] if (need-to-backtrack) [backtrack] set-current-plot "Message-queue" set-current-plot-pen (word who) plot length message-queue ] set done reduce [?1 and ?2] [dead] of nodes type time type "- " ask nodes [ type position color domain type " " ] print "" if (done) [stop] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Map data structure to-report make-map report [] end to-report get-triple-index [map-name key1 key2] let i 0 set i 0 while [i < length map-name][ if (item 0 item i map-name = key1 and item 1 item i map-name = key2) [ report i] set i i + 1 ] report -1 end to-report set-map-value [map-name key1 key2 value] let triple-index 0 set triple-index get-triple-index map-name key1 key2 ifelse (triple-index = -1) [ report lput (list key1 key2 value) map-name ][ report replace-item triple-index map-name (list key1 key2 value) ] end to-report get-map-value [map-name key1 key2] let i 0 set i 0 while [i < length map-name][ if (item 0 item i map-name = key1 and item 1 item i map-name = key2) [ report item 2 item i map-name] set i i + 1 ] report [] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Context data structure . to-report make-context report make-list num-nodes -1 end to-report add-to-context [cont v val] report replace-item v cont val end to-report remove-from-context [cont v] report replace-item v cont -1 end ;a vertice function to-report add-my-value-to-context [cont] report replace-item who cont color end to-report compatible? [a b] let i 0 set i 0 set AgentC_Cost AgentC_Cost + 1 while [i < num-nodes][ if (item i a != -1 and item i b != -1 and item i a != item i b)[ report false] set i i + 1 ] report true end ;assumes a and b are compatible to-report union [a b] let c 0 let i 0 set c make-context set i 0 while [i < num-nodes][ if (item i a != -1) [ set c replace-item i c (item i a)] if (item i b != -1) [ set c replace-item i c (item i b)] set i i + 1 ] report c end ;returns a list of the who of the agents in the context to-report agents-in-context [cont] let i 0 let res 0 set i 0 set res [] while [i < num-nodes][ if (item i cont != -1)[ set res lput i res ] set i i + 1 ] report res end ;;;Adopt procedures ;Reports wether or not v is an ancestor of i or is i. to-report ancestor? [v i] if ([who] of v) = ([who] of i) [report true] if ([parent] of i = -1 or [parent] of i = -2) [report false] report ancestor? v ([parent] of i) end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;DFS Algorithm by Jay Modi with a change by jmv ;It does not always work (there might not be a constraint between parent-child) ;but we "fix" this by adding a constraint between all parent-childs (they are all random graphs anyway ;-) to send-parent-message let parents 0 set parents filter [? < who] dfs-neighbors ;show (word "Parents" parents) ifelse (empty? parents) [ set parent -1 ;the root ][ if (dfs-change) [ ;jmv added dfs-change variable set parent max parents send-message parent (filter [? < who] dfs-neighbors) ] ] end to handle-dfs-message set dfs-change false ;show (word "Coada de " message-queue) if (not empty? message-queue)[ if (not empty? filter [not member? ? dfs-neighbors] (first message-queue))[ set dfs-change true set dfs-neighbors remove-duplicates sentence dfs-neighbors (first message-queue) ] set message-queue butfirst message-queue] end to set-dfs-tree let child 0 let nm 0 ask-concurrent nodes [ set dfs-neighbors neighbors-list set parent -2 set children [] set message-queue [] set dfs-change true send-parent-message ] while [any? nodes with [not empty? message-queue]][ ask-concurrent nodes [ handle-dfs-message send-parent-message ] ] ;ugly hack: add an edge between any parent-child that does not have one ask nodes [ if (parent != -1 and (not member? parent neighbors-list))[ make-link who parent set neighbors-list lput parent neighbors-list set nm who ask turtle parent [set neighbors-list lput nm neighbors-list ] show (word "Added extra edge " who " - " parent) ] ] ;sets the parent-agent and children ask nodes [ if (parent != -1) [ set parent-agent (turtle parent) set child who ask turtle parent [ set children fput child children ] ] ] ;sets children-agent and descendant-neigbors ask nodes [ set children-agent (nodes with [member? who ([children] of myself)]) set-descendant-neighbors ] end ;;;Tree utility functions ;report true if id is a descendant of node to-report is-descendant? [node id] if (member? id ([children] of (turtle node))) [ report true] if (not empty? ([children] of (turtle node)))[ report reduce [?1 or ?2] map [is-descendant? ? id] ([children] of (turtle node)) ] report false end to set-descendant-neighbors set descendant-neighbors [] foreach neighbors-list [ if (is-descendant? who ?) [ set descendant-neighbors lput ? descendant-neighbors ] ] end ;vertice procedures to send-message [receiver msg] if (show-messages) [show (word "sendto " receiver "-" msg)] ;set [message-queue] of (turtle receiver) lput msg ([message-queue] of (turtle receiver)) ask turtle receiver[ set message-queue lput msg message-queue ] ;set [messages-received] of (turtle receiver) [messages-received] of (turtle receiver) + 1 ask turtle receiver [ set messages-received messages-received + 1] end to send-priority-message [receiver msg] if (show-messages) [show (word "sendto " receiver "-" msg)] ask turtle receiver [ set message-queue fput msg message-queue ] end ;delta ;The local-cost is the total number of neighbors with color of d to-report local-cost [d] let cost 0 set cost 0 foreach neighbors-list [ if ((item ? current-context != -1) and item ? current-context = d)[ set cost cost + 1 ] ] report cost end ;LB(d) from the paper. to-report LBd [d] let bound 0 set bound local-cost d foreach children [ set bound bound + get-map-value lbounds d ? ] report bound end ;UB(d) from The paper. to-report UBd [d] let bound 0 set bound local-cost d foreach children [ set bound bound + get-map-value ubounds d ? ] report bound end to-report UBmin let minarg 0 let minval 0 let val 0 set minval 99 foreach domain [ set val UBd ? if (val < minval)[ set minval val set minarg ? ] ] report list minarg minval end to-report UB report item 1 UBmin end to-report UBarg report first UBmin end to-report LBmin let minarg 0 let minval 0 let val 0 set minval 99 foreach domain [ set val LBd ? if (val < minval)[ set minval val set minarg ? ] ] report list minarg minval end to-report LB report item 1 LBmin end to-report LBarg report first LBmin end to initialize let d 0 let xl 0 set threshold 0 set current-context make-context set last-threshold-message make-list num-nodes [] foreach domain [ set d ? foreach children [ set xl ? set lbounds set-map-value lbounds d xl 0 set ubounds set-map-value ubounds d xl 99 set t set-map-value t d xl 0 set context set-map-value context d xl make-context ] ] backtrack ;instead of doing backtrack, I just send the messages. This way we make sure they go out even if the color does not change. ; foreach descendant-neighbors [ ; send-message ? (list "value" who color) ; ] ; if (parent != -1) [ ; send-message parent (list "cost" who current-context LB UB) ; ] end to handle-message let msg 0 let mt 0 let SenderC_Cost 0 if (dead) [stop] if (not empty? message-queue)[ set msg first message-queue set mt first msg if (mt = "cycle") [stop] set message-queue butfirst message-queue set messages-handled messages-handled + 1 set SenderC_Cost last msg if SenderC_Cost > AgentC_Cost [ set AgentC_Cost SenderC_Cost ] if (mt = "threshold")[ handle-threshold msg stop] if (mt = "terminate")[ handle-terminate msg stop] if (mt = "value")[ handle-value msg stop] if (mt = "cost")[ handle-cost msg stop] show (word "ERROR: Bad Message " mt) ] end to handle-threshold [msg] if (show-messages) [show (word "handle-threshold " msg)] if (compatible? (item 2 msg) current-context)[ set threshold item 1 msg maintain-threshold-invariant set need-to-backtrack true ] end to handle-terminate [msg] if (show-messages) [show (word "handle-terminate " msg)] set terminate true set current-context (item 1 msg) set need-to-backtrack true end to handle-value [msg] let d 0 if (show-messages) [show (word "handle-value " msg)] if (not terminate)[ set current-context add-to-context current-context (item 1 msg) (item 2 msg) foreach domain [ set d ? foreach children [ if (not compatible? (get-map-value context d ?) current-context) [ set lbounds set-map-value lbounds d ? 0 set t set-map-value t d ? 0 set ubounds set-map-value ubounds d ? 99 set context set-map-value context d ? make-context ] ] ] maintain-threshold-invariant set need-to-backtrack true ] end to handle-cost [msg] let d 0 let xk 0 let dprime 0 let msg-context 0 let i 0 if (show-messages) [show (word "handle-cost " msg)] set msg-context (item 2 msg) set d (item who msg-context) set msg-context remove-from-context msg-context who if (not terminate)[ foreach (filter [not member? ? neighbors-list] (agents-in-context msg-context))[ set current-context (add-to-context current-context ? (item ? msg-context)) ] foreach domain [ set dprime ? foreach children [ if (not compatible? (get-map-value context dprime ?) current-context)[ set lbounds set-map-value lbounds dprime ? 0 set t set-map-value t dprime ? 0 set ubounds set-map-value ubounds dprime ? 99 set context set-map-value context dprime ? make-context ] ] ] ] set xk (item 1 msg) if (d != -1 and compatible? msg-context current-context)[ ;jmv added d!=1 set lbounds set-map-value lbounds d xk (item 3 msg) set ubounds set-map-value ubounds d xk (item 4 msg) set context set-map-value context d xk msg-context maintain-child-threshold-invariant maintain-threshold-invariant ] set need-to-backtrack true end to backtrack let old-color 0 let the-UB 0 set the-UB UB set old-color color ; if (show-messages) [show "backtrack"] ifelse (threshold = the-UB) [ set color UBarg ][ if (LBd color > threshold) [ set color LBarg ] ] ; if (old-color != color)[ ;Added by jmv--not part of the published Adopt foreach descendant-neighbors [ send-message ? (list "value" who color AgentC_Cost) ; ] ] maintain-allocation-invariant if (threshold = the-UB) and (terminate or parent = -1) [ foreach children [ send-message ? (list "terminate" (add-my-value-to-context current-context) AgentC_Cost) ] set dead true set terminate true stop ] if (parent != -1) [ send-message parent (list "cost" who current-context LB the-UB AgentC_Cost) ] end to maintain-threshold-invariant if (threshold < LB)[ set threshold LB ] if (threshold > UB)[ set threshold UB ] end to maintain-allocation-invariant let sum-of-t 0 let chosen-child 0 let last-sent 0 set sum-of-t sum map [get-map-value t color ?] children while [threshold > local-cost color + sum-of-t][ set chosen-child one-of (children-agent with [get-map-value ([ubounds] of myself) ([color] of myself) who > get-map-value ([t] of myself) ([color] of myself) who]) set t set-map-value t color ([who] of chosen-child) (1 + get-map-value t color ([who] of chosen-child)) set sum-of-t sum map [get-map-value t color ?] children ] set sum-of-t sum map [get-map-value t color ?] children while [threshold < local-cost color + sum-of-t][ set chosen-child one-of children-agent with [get-map-value ([t] of myself) ([color] of myself) who > get-map-value ([lbounds] of myself) ([color] of myself) who] set t set-map-value t color ([who] of chosen-child) (get-map-value t color ([who] of chosen-child) - 1) set sum-of-t sum map [get-map-value t color ?] children ] foreach children [ set last-sent item ? last-threshold-message ;last thresold message sent to this agent ; if (empty? last-sent or first last-sent != (get-map-value t color ?) or (not lists-equal? current-context (item 1 last-sent)))[ ;jmv added. Only send if msg different from previous one send-message ? (list "threshold" (get-map-value t color ?) current-context AgentC_Cost) ; set last-threshold-message replace-item ? last-threshold-message list (get-map-value t color ?) current-context ; ] ] end to maintain-child-threshold-invariant let d 0 foreach domain [ set d ? foreach children [ while [get-map-value lbounds d ? > get-map-value t d ?][ set t set-map-value t d ? (get-map-value t d ? + 1) ] ] ] foreach domain [ set d ? foreach children [ while [get-map-value t d ? > get-map-value ubounds d ?][ set t set-map-value t d ? (get-map-value t d ? - 1) ] ] ] end