breed [ subjects ] ;; simulate individual members breed [ messages ] ;; simulate messages posted by members breed [ links link ] ;; simulate connections among members globals [ ;; global variables required to set up and run the model - see below for definitions and values ticks run-number exp-index output-subject output-message output-interact output-benefit output-ticksum output-statsum1 output-statsum2 max-sub-id max-mess-id max-link-id max-mess-age max-inactive-sub max-inactive-mess max-benefit ideal-size reg-cost comm-cost moderation personalize filter-precision scan-scope reply-threshold offtopic-interest design-delay incubation mess-weight-delta link-mean popular-mean newtopics newontopics max-messages ;; total number of messages the community technology can support beyond which old messages will be removed max-newcomer ;; max number of newcomers at each tick (each tick simulates a day in real life) newcomer ;; number of newcomers joining the group at each tick newposters ;; number of new posters who delurked at tick t lurkleave ;; number of lurkers who leave the community at tick t postleave ;; number of posters who leave the community at tick t newcomer-rate ;; rate at which newcomers join, can be set to equal to 1/3/5 info-perc ;; community level preference of information benefits fun-perc ;; community level preference of recreational benefits bond-perc ;; community level preference of bonding benefits iden-perc ;; community level preference of identity benefits group-size ;; total number of active members tick-parts ;; total number of participants at each tick tick-conts ;; total number of contributors at each tick tick-posts ;; total number of posts posted at each tick tick-threads ;; total number of new threads posted at each tick tick-links ;; total number of replies or links created at each tick contributors ;; active members who are not lurkers meaning they have posted at least one message close-size ;; number of active contributors (used in calculating interpersonal bonds benefits) message-all ;; total number of messages currently accessible in the community distract-alpha ;; equal to 2 for support and political discussion communities and 3 for technical and interest communities distract-beta ;; 0.5 for reasonable distraction and 1 for extreme distraction topic-breadth ;; number of topics covered by the community ] subjects-own [ subjectid ;; unique id for subjects ;; the following variables are intrinsic attributes of individual agents which are static w-info ;; individual preference for information benefits w-fun ;; individual preference for fun of reading and posting messages w-bond ;; individual preference for bonds / friendship benefits w-iden ;; individual preference for identity / sense of belonging benefits passion ;; how much the agent enjoys reading and posting messages interest ;; a list of topics the agent is interested (0 indicating off-topic) interest-breadth ;; number of topics interested interest-list ;; a list of all topics the subject is interested distract ;; level of distraction of the member (simulate opportunity costs of participating) altruism ;; willingness to help others or to share one's opnions ;; the following variables track the state and activity of an agent over time createdate ;; tick at which a member is created membership ;; if 1 then an active member if 0 then an inactive member inactive ;; keep track of the periods of no activity islurker ;; 1 changed to 0 once the member posts one's first message history-tick ;; member age or tenure in the community history-part ;; number of ticks that member participated history-cont ;; number of ticks that member contributed message-self ;; number of total messages the agent has contributed firstpart ;; first tick at which a member participated firstcont ;; first tick at which a member contributed latestpart ;; latest tick at which a member participated latestcont ;; latest tick at which a member contributed ;; the following varialbes track experiences of agents and determine their next-step actions info-b-self ;; benefit from accessing valuable info info-tocomp ;; benefit from providing info fun-b-doing ;; benefit from enjoyment of reading and posting reputation-b ;; benefit from being recognized as a successful member bond-b ;; benefit from liking and feeling attached to members iden-b ;; benefit from identifying and feeling attached to group famsize ;; size of members in the subject's close friend circle p-costs ;; costs of participating during the current or most recent tick c-costs ;; costs of contributing during the current or most recent tick p-benefits ;; benefits from participation of the current or most recent tick c-benefits-both ;; benefits that motivate both posting new and replying (1/3 info-self and 2/3 info-tocomp) lastresponses ;; number of replies to the subject during the last tick nowresponses ;; number of replies to the subject during the current tick first-viewed-topic ;; list of messages under each topic first-viewed-count ;; total number of messages read during first exposure first-viewed-on ;; percentage of on-topic messages read during first exposure first-info-b ;; benefit from accessing valuable info during first exposure first-tocomp ;; benefit from providing info during first exposure first-fun-b ;; benefit from enjoyment of reading and posting during first exposure first-bond-b ;; benefit from liking and feeling attached to members during first exposure first-iden-b ;; benefit from identifying and feeling attached to group during first exposure ] messages-own [ ;; attributes of messages messageid ;; each message has a unique message id thread ;; message id of the thread which the message belongs to parent ;; message id of the parent message poster ;; subject id of the agent who posts the message topic ;; topic of the message, between 0 and topic-breadth age ;; number of ticks since being created question ;; 1 for a question and 0 otherwise popularity ;; number of responses to the message createtick ;; tick at which the message is created latesttick ;; tick at which the message receives the latest response scanindex ;; used when searching for messages to reply to ] links-own [ ;; attributes of links linkid ;; each link gets a uniq link id linkage ;; number of ticks since being created getold ;; number of ticks since last refreshed frequency ;; frequency of links between two agents (directional) ] to setup clear-turtles clear-patches clear-output clear-all-plots set run-number (run-number + 1) ;; the following statements specify the initial condition to run the model ;; they are now commented meaning you can set the parameters using the interface or the Behavior Space ;; when they are not commented, they will override the input from the interface or the Behavior Space set initial-members item exp-index (list 30 30 30 30) set initial-messages item exp-index (list 30 30 30 30) set run-time item exp-index (list 300 300 300 300) set comm-type item exp-index (list "technical" "interest" "support" "political") ;; the following are parameters that we manipulated in our virtual experiments ;; the statements need to be commented if you were to vary them to run experiments using the Behavior Space set comm-cost 1.5 ;; cost of contribution to post a message (values we experimented with are 1 / 1.5 / 2) set topic-breadth 5 ;; number of nominal topics (values we experimented with are 1, 5, 9) set moderation "no" ;; whether to pre-filter at the community level set personalize "no" ;; whether to have personalized view set reg-cost 0.5 ;; cost of participation such as accessing website and signing in set offtopic-interest 0.1 ;; members' likelihood of being interested in off-topic discussion set filter-precision 1 ;; precision of personalized recommendation % of recommended messages that match memeber interests set ticks 0 set group-size 0 ;; set group size to zero set max-sub-id 0 ;; keep track of the highest subjectid set max-mess-id 0 ;; keep track of the highest messageid set max-link-id 0 ;; keep track of the highest linkid set max-mess-age 0 ;; keep track of the maximum age of all active messages ;; defined constants such as default start values and upper limit values set max-benefit 10 ;; threadshold to all benefits set output-subject true ;; when TRUE print poster-stat.txt (attributes and activities of all active agents) set output-message false ;; when TRUE print post-stat.txt (attributes of all messages including ones being removed) set output-interact false ;; when TRUE print interact.txt (attributes of all active links) set output-benefit true ;; when TRUE print periodic benefit report (benefits experienced by agents at various times) set output-ticksum true ;; when TRUE print all community statistics at each tick (e.g., number of messages posted) set output-statsum1 false ;; when TRUE print statsum1.txt (output community statistics BEFORE agents decide whether to participate for each tick) set output-statsum2 false ;; when TRUE print statsum2.txt (output community statistics at the end of each tick) set max-messages 5000 ;; maximum number of messages displayed to agents, once above, start removing oldest messagess set max-inactive-sub 600 ;; users counted as having left after 600 rounds of no participation (based on evidence from netscan data) set max-inactive-mess 10 ;; messages not responded within last 10 days unlikely to be read or responded to set max-newcomer 50 ;; maximum number of newcomers allowed for each tick / day set ideal-size 15 ;; ideal group size to maintain relational intimacy among members set mess-weight-delta 0.5 ;; when choosing message to respond to, weight given to certain criteria in diff types of communities (see below for detail) set incubation 0 ;; newcomers need to participate N times before they can post (currently not used) set newcomer-rate 5 ;; control the rate at which newcomers join - 5 is the default (could also be set to 1 or 3) set scan-scope 30 ;; number of messages that an agent scans to select a message to respond to set reply-threshold 0 ;; used to determine which message to respond to - when index-value of a message is greater than reply-threshold set design-delay 60 ;; N ticks of delay before design interventions take effects, e.g., due to lack of data ;; the following two parameters simulate opportunity costs, with a gamma distribution set distract-alpha 5 ;; alpha of the gamma distribution set distract-beta 1 ;; beta of the gamma distribution ;; we assume preferences for diff kinds of benefits vary across communities ;; research has shown members join different types of online communities for diff reasons ;; we use survey results from (Ridings & Gefen 2004) to set the parameters if comm-type = "technical" [ set info-perc 0.55 set fun-perc 0.10 set bond-perc 0.10 set iden-perc 0.25 ] if comm-type = "support" [ set info-perc 0.40 set fun-perc 0.05 set bond-perc 0.15 set iden-perc 0.30 ] if comm-type = "interest" [ set info-perc 0.50 set fun-perc 0.10 set bond-perc 0.30 set iden-perc 0.10 ] if comm-type = "political" [ set info-perc 0.30 set fun-perc 0.15 set bond-perc 0.30 set iden-perc 0.20 ] if comm-type = "movielens" [ set info-perc 0.60 set fun-perc 0.15 set bond-perc 0.10 set iden-perc 0.30 ] ;; create seed messages set-default-shape messages "circle" repeat initial-messages [ create-custom-messages 1 [ set messageid max-mess-id set max-mess-id (max-mess-id + 1) set age 0 set thread -1 set parent -1 set poster -1 set topic (random topic-breadth) set question 0 set popularity 0 set createtick ticks set latesttick -1 set size 0.1 set hidden? not hidden? ] ] ;; create seed members set-default-shape subjects "person" create-custom-subjects initial-members [ set subjectid max-sub-id set max-sub-id (max-sub-id + 1) set size 1 ;; makes them easier to see set color grey ;; default color for user ;; randomly place agents on the grid set xcor random world-width set ycor random world-height set islurker 1 set membership 1 set inactive 0 set history-tick 0 set history-part 0 set history-cont 0 set createdate 0 set firstpart -1 set firstcont -1 set latestpart -1 set latestcont -1 set fun-b-doing 0 set reputation-b 0 set info-b-self 0 set info-tocomp 0 set bond-b 0 set iden-b 0 set message-self 0 ;; randomly set opportunity cost of individual agent set distract ((10 - random-gamma distract-alpha distract-beta) / 2) if distract < 0 [ set distract (random-float 5 - 1)] ;; an individual agent may be interested in any of the nomimal topics and may or may not be interested in off-topic set interest-breadth round random-normal (topic-breadth / 2) ((topic-breadth / 2 - 1) / 2) if (interest-breadth < 0 or interest-breadth > topic-breadth) [ set interest-breadth random topic-breadth ] set interest n-values topic-breadth [ 0 ] let totalones 0 let whichposition random topic-breadth while [totalones < interest-breadth] [ if (item whichposition interest = 0) [ set interest (replace-item whichposition interest 1) set totalones (totalones + 1) ] set whichposition random topic-breadth ] ifelse (random-float 1 < offtopic-interest) [ set interest (replace-item 0 interest 1) ] [ set interest (replace-item 0 interest 0) ] ;; agents of technical communites are generally not interested in off-topic messages if (comm-type = "technical") [ set interest (replace-item 0 interest 0) ] set interest-list n-values 0 [0] let whichtopic 0 foreach interest [ if (? > 0) [ set interest-list lput whichtopic interest-list ] set whichtopic (whichtopic + 1) ] ;; passion indicates how much an agent enjoys reading messages ;; we assume it follows a gamma distribution with most agents having a modarate level of enjoyment and few having high levels of enjoyment set passion random-gamma 3 1 ifelse passion >= 4 ;; red > orange > yellow in terms of enjoyment of reading [ ifelse passion >= 7 [ set color blue ] [ set color red ] ] [ set color yellow ] ifelse (random-float 1 < 0.01) [ set altruism 1 ] [ set altruism 0 ] ;; individual preferences for various benefits are normally distributed around community means set w-info max (list 0.01 random-normal info-perc 0.05) set w-fun max (list 0.01 random-normal fun-perc 0.05) set w-bond max (list 0.01 random-normal bond-perc 0.05) set w-iden max (list 0.01 random-normal iden-perc 0.05) set lastresponses 0 set nowresponses 0 ] setup-plots file-close-all ;; if (file-exists? "post-stat.txt") [ file-delete "post-stat.txt" ] ;; if (file-exists? "statsum1.txt") [ file-delete "statsum1.txt" ] ;; if (file-exists? "statsum2.txt") [ file-delete "statsum2.txt" ] ;; if (file-exists? "interact.txt") [ file-delete "interact.txt" ] end to go if ticks = run-time [ if (output-subject = true) [ ;; output all active agents together with experimental parameters file-open "poster-stat.txt" ask subjects [ file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + subjectid + " " + (precision w-info 3) + " " + (precision w-fun 3) + " " + (precision w-bond 3) + " " + (precision w-iden 3) + " " + (precision passion 3) + " " + interest-breadth + " " + (precision distract 3) + " " + history-tick + " " + history-part + " " + history-cont + " " + message-self + " " + createdate + " " + firstpart + " " + firstcont + " " + latestpart + " " + latestcont + " " + membership + " " + first-viewed-count + " " + (precision first-viewed-on 3) + " " + (precision first-info-b 3) + " " + (precision first-tocomp 3) + " " + (precision first-fun-b 3) + " " + (precision first-bond-b 3) + " " + (precision first-iden-b 3) + " " + (precision info-b-self 3) + " " + (precision info-tocomp 3) + " " + (precision fun-b-doing 3) + " " + (precision reputation-b 3) + " " + (precision bond-b 3) + " " + (precision iden-b 3) + " " + (precision p-benefits 3) + " " + (precision c-benefits-both 3) + " " file-print famsize ] file-close ] if (output-message = true) [ ;; output all active messages together with experimental parameters file-open "post-stat.txt" ask messages [ file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + messageid + " " + thread + " " + parent + " " + poster + " " + topic + " " + question + " " + popularity + " " + createtick + " " + latesttick + " " + age file-print " 0" ] file-close ] stop ] ;; the following parameters are used to track events and statistics for the current tick set tick-parts 0 ;; track number of agents who will participate set tick-conts 0 ;; track number of agents who will contribute set tick-posts 0 ;; track number of posts that will be posted set tick-threads 0 ;; track number of new threads that will be started set tick-links 0 ;; track number of links that will be formed or refreshed set newcomer -1 ;; track number of newcomers who will join set newposters 0 ;; track number of agents who will post their first message set lurkleave 0 ;; track number of lurkers who will leave or become inactive set postleave 0 ;; track number of posters who will leave or become inactive ;; the following parameters are used to ... set newtopics n-values topic-breadth [0] ;; close-size counts number of active contributor and group-size counts number of active participants set contributors subjects with [membership = 1 and islurker = 0 and history-cont > 3] set close-size max (list 1 count contributors) set group-size count subjects with [membership = 1] set message-all count messages set max-mess-age max values-from messages [age] ;; link-mean is the average strength of all links ;; used to assess reciprocity when deciding which message to respond to (see below for detail) if (length values-from links [frequency] > 1) [ set link-mean mean values-from links [frequency] ] if (link-mean = 0) [ set link-mean 1 ] ;; count average popularity of messages with replies ;; used to assess popularity when deciding which message to respond to (see below for detail) let msgwreply messages with [popularity > 0] if (length values-from msgwreply [popularity] > 1) [ set popular-mean mean values-from msgwreply [popularity] ] if (popular-mean = 0) [ set popular-mean 1 ] ;; calculate familarity for bond-b - see calculate-familiarsize for detail ask subjects with [membership = 1] [ set lastresponses nowresponses set nowresponses 0 calculate-familiarsize ] ;; output summary statistics of members and posts before member decisions and actions if (output-statsum1 = true) [ file-open "statsum1.txt" file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + (count subjects) + " " + (count subjects with [membership = 1]) + " " + (count subjects with [history-part > 0]) + " " + (count subjects with [islurker = 0]) + " " + close-size + " " + (count messages) + " " + (count messages with [parent = -1]) + " " + (count links) + " " + (precision link-mean 3) + " " file-print (precision popular-mean 3) file-close ] ;; individual agents decide whether to participate or contribute for the current tick ;; this is the core of the model, please refer to the decide method for detail of how benefits and costs are calculated ask subjects with [membership = 1] [ decide ] ;; for all agents, check whether their status should be changed to inactive ;; change the status to inactive if an agent has not been posting for 30 days and have not been participating for a long time ;; the second component is stochastic - the longer one has been inactive, the less likely one would return in the future ;; when an agent become active, links connected to or from the agent become inactive too ask subjects with [membership = 1] [ ifelse (ticks - latestcont > (max-inactive-sub / 20) and random-float 1 < (inactive / max-inactive-sub)) [ if (count __my-in-links > 0) [ __remove-links-from __in-link-neighbors ] if (count __my-out-links > 0) [ __remove-links-to __out-link-neighbors ] ifelse (history-cont < 1) [ set lurkleave (lurkleave + 1) ] [ set postleave (postleave + 1) ] set membership 0 hideturtle ] [ if (p-benefits < 0) [ if (count __my-in-links > 0) [ __remove-links-from __in-link-neighbors ] if (count __my-out-links > 0) [ __remove-links-to __out-link-neighbors ] ifelse (history-cont < 1) [ set lurkleave (lurkleave + 1) ] [ set postleave (postleave + 1) ] set membership 0 hideturtle ] ;; end of if loop ] ;; end of ifelse loop ] ;; end of ask subjects ask links [ set getold (getold + 1) ;; temporarily commented so that links do not age or die for now ;; if (getold > 300) [ set frequency max (list 0 (frequency - 1)) ] ;; if frequency <= 0 [die] ] ;; when number of message is over the limit of max-messages, start removing messages from the oldest to the newest if (count messages > max-messages) [ ask messages with [age >= (max-mess-age - 10)] [ ;; messages with response within the past and current ticks will not die ;; (ticks - latesttick) = 0 if latest response in current tick and 1 if latest response in the previous tick if (latesttick = -1 or ticks - latesttick > max-inactive-mess) [ if (output-message = true) [ ;; output information about the message that is being removed file-open "post-stat.txt" file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + messageid + " " + thread + " " + parent + " " + poster + " " + topic + " " + question + " " + popularity + " " + createtick + " " + latesttick + " " + age file-print " 1" file-close ] die ] ;; end of if (ticks - latesttick > 1) ] ;; end of ask messages ;; if there are still more messages above max-message, remove more if (count messages > max-messages) [ ask n-of (5 * (count messages - max-messages)) messages [ if (latesttick = -1 or ticks - latesttick > max-inactive-mess) [ if (output-message = true) [ ;; output information about the message that is being removed file-open "post-stat.txt" file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + messageid + " " + thread + " " + parent + " " + poster + " " + topic + " " + question + " " + popularity + " " + createtick + " " + latesttick + " " + age file-print " 1" file-close ] die ] ;; end of if (ticks - latesttick > 1) ] ;; end of ask messages ] ;; end of if (count messages > max-messages) ] ;; end of while loop ask messages [ set age (age + 1) ;; survived messages get one tick older ] ask links [ set linkage (linkage + 1) ] ;; community considered as having failed without more than 3 active members or 10 active messages if (ticks > 30 and close-size < 3 and message-all < 10) [ output-show ("The community failed due to lack of member contribution!") stop ] ;; output summary statistics of members and posts at the end of each tick if (output-statsum2 = true) [ file-open "statsum2.txt" file-type run-number + " " + comm-type + " " + ticks + " " + initial-members + " " + initial-messages + " " + newcomer-rate + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + offtopic-interest + " " + filter-precision + " " + run-time + " " + reg-cost + " " + comm-cost + " " + distract-alpha + " " + distract-beta + " " + (count subjects with [membership = 1]) + " " + tick-parts + " " + tick-conts + " " + tick-posts + " " + tick-threads + " " + newcomer + " " + newposters + " " + lurkleave + " " + postleave + " " file-print (count messages) file-close ] ;; calculate and output statistics of each tick ;; percentage of on-topic messages newly posted if (sum newtopics > 0) [ set newontopics (sum newtopics - item 0 newtopics) / (sum newtopics) ] ;; summary statistics of all posters - only for output, not used in modeling let posters subjects with [membership = 1 and islurker = 0] let totalposters (count posters) let posterinterests -1 if (length values-from posters [interest-breadth] > 1) [ set posterinterests mean values-from posters [interest-breadth] ] ;; summary statistics of all links - only for output, not used in modeling let totallinks (count links) let linkstrengthavg -1 let linkstrengthstd -1 if (length values-from links [frequency] > 1) [ set linkstrengthavg mean values-from links [frequency] set linkstrengthstd standard-deviation values-from links [frequency] ] ;; print activity, interactivity, and newcomer statistucs at each tick file-open "ticksum.txt" file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + tick-conts + " " + tick-posts + " " + tick-threads + " " + newontopics + " " + newposters + " " + tick-links + " " + message-all + " " + close-size + " " + totalposters + " " + posterinterests + " " + totallinks + " " + linkstrengthavg + " " file-print linkstrengthstd file-close set ticks (ticks + 1) ;; create newcomers who will join for the new tick ;; Basedon analyis of UseNet groups, we assume that (1) community without active members or messages will NOT attract any newcomers ;; (2) the number of newcomers follow a gamma distribution with diff alpha and beta values depending on types and size of community ;; (3) alpha and beta are determined by the existing size of the community, larger groups tend to attract more newcomers if (tick-parts > 0 and message-all > 0) [ let newcomer-alpha 1 let newcomer-beta 2 if (comm-type = "interest") [ set newcomer-alpha (2.5 + 0.005 * group-size) set newcomer-beta (newcomer-alpha - 1) ] if (comm-type = "political") [ set newcomer-alpha (1.2 + 0.009 * group-size) set newcomer-beta (0.6 * newcomer-alpha) ] if (comm-type = "support") [ set newcomer-alpha (1.5 + 0.007 * group-size) set newcomer-beta (0.6 * newcomer-alpha) ] if (comm-type = "technical") [ set newcomer-alpha (1.5 + 0.008 * group-size) set newcomer-beta (0.6 * newcomer-alpha) ] set newcomer round (newcomer-rate * random-gamma newcomer-alpha newcomer-beta) if (newcomer > max-newcomer) [ set newcomer max-newcomer ] create-custom-subjects newcomer [ set subjectid max-sub-id set max-sub-id (max-sub-id + 1) set size 1 ;; makes them easier to see set color grey ;; default color for member set xcor random world-width set ycor random world-height set islurker 1 set membership 1 set inactive 0 set history-tick 0 set history-part 0 set history-cont 0 set createdate ticks set firstpart -1 set firstcont -1 set latestpart -1 set latestcont -1 set fun-b-doing 0 set reputation-b 0 set info-b-self 0 set info-tocomp 0 set bond-b 0 set iden-b 0 set message-self 0 set distract ((10 - random-gamma distract-alpha distract-beta) / 2) if distract < 0 [ set distract (random-float 5 - 1)] set interest-breadth round random-normal (topic-breadth / 2) ((topic-breadth / 2 - 1) / 2) if (interest-breadth < 0 or interest-breadth > topic-breadth) [ set interest-breadth random topic-breadth ] set interest n-values topic-breadth [ 0 ] let totalones 0 let whichposition random topic-breadth while [totalones < interest-breadth] [ if (item whichposition interest = 0) [ set interest (replace-item whichposition interest 1) set totalones (totalones + 1) ] set whichposition random topic-breadth ] ifelse (random-float 1 < offtopic-interest) [ set interest (replace-item 0 interest 1) ] [ set interest (replace-item 0 interest 0) ] if (comm-type = "technical") [ set interest (replace-item 0 interest 0) ] set interest-list n-values 0 [0] let whichtopic 0 foreach interest [ if (? > 0) [ set interest-list lput whichtopic interest-list ] set whichtopic (whichtopic + 1) ] set passion random-gamma 3 1 ifelse passion >= 4 ;; red > orange > yellow [ ifelse passion >= 7 [ set color blue ] [ set color red ] ] [ set color yellow ] ifelse (random-float 1 < 0.01) [ set altruism 1 ] [ set altruism 0 ] set w-info max (list 0.01 random-normal info-perc 0.05) set w-fun max (list 0.01 random-normal fun-perc 0.05) set w-bond max (list 0.01 random-normal bond-perc 0.05) set w-iden max (list 0.01 random-normal iden-perc 0.05) set lastresponses 0 set nowresponses 0 ] ] ;; end of if (tick-parts> 0 and message-all > 0) update-plots end to decide ;; subjects procedure - to caculate benefits and costs, and determine participation and contribution ;; opportunity cost captures other things going on in members lives that compete for time ;; opportunity cost could be negative meaning some extra time to kill for instance ;; distract indicates on average how busy an agent is, opportunity cost for a tick is a normal distribution around it let oppor-cost 0 set oppor-cost (random-normal distract 2) set p-costs (reg-cost + 0.5 * oppor-cost) set c-costs (reg-cost + oppor-cost) let search-cost 0 ;; motivation to read depends on previously experienced benefits in info, fun, bond and identity ;; it can be motivated by the benefit of receiving information or the benefit of sharing information alone, ;; which is why we use the higher value of info-b-self and info-tocomp set p-benefits ( (w-info * max (list info-b-self info-tocomp)) + (w-fun * fun-b-doing) + (w-iden * iden-b) + (w-bond * bond-b) ) / (w-info + w-fun + w-iden + w-bond) ;; assume all newcomers participate at the tick when they join the group to check it out (otherwise they will not be a newcomer) ;; history-tick is the tenure of an agent - when it is zero, set p-benefits above p-costs so they will for sure participate if (history-tick = 0 and p-benefits < p-costs) [set p-benefits (p-costs + random-float 2) ] ;; members participate if members feeel expected benefits exceed costs of participating ifelse (p-benefits >= p-costs) [ if (history-part = 0) [ set firstpart ticks ] ;; the first tick at which an agent participated in the community set history-part (history-part + 1) ;; agent hitory of participating increased by 1 set tick-parts (tick-parts + 1) ;; total number of participants in this tick increased by 1 let lastvisit latestpart ;; track when the person last participated (so as to know what messages to show later) set latestpart ticks ;; update the latest tick at which a member participated to the current tick ;; members get real benefits from accessing info and interacting with other members ;; based on their experienced benefits of all they decide whether to post messages or not ;; interest is a list of nominal topics, the element is set to 1 if an agent is interested in the topic, otherwise it is set to 0 ;; interest-list is a list of numbers, each number representating a topic the agent is interested in ;; the two capture the same information but are different. Consider an agent with an "interest" of [1, 0, 0, 1, 1, 0] in a community with 6 topics ;; the interest-list of the agent is [0, 3, 4] indicating the agent has an interest in topic 0, 3, and 4. let self-interest interest let self-intrlist interest-list ;; the following calculates the number of messages an agent will read and the benefits and costs of doing so let mess-viewed nobody ;; messages viewed let mess-viewed-on 0 ;; number of viewed messages that are on-topic let mess-viewed-count 0 ;; number of total viewed messages, including both on-topic and off-topic ones let mess-viewed-topic n-values topic-breadth [0] ;; an array indicating topics of messages viewed ;; readback determines the date since which to retrieve messages ;; it is either up until 10 days ago given max-inactive-mess = 10 or since the agent's last visit let readback min (list max-inactive-mess (ticks - lastvisit)) ;; latest messages refer to those posted during the last tick ;; recent messages refer to those posted since the agent's last visit yet older than 1 tick let latest-toview nobody ;; latest messages to be viewed let recent-toview nobody ;; recent messages to be viewed let latest-mess-count 0 ;; count of latest messages to be viewed let recent-mess-count 0 ;; count of recent messages to be viewed let recent-toview-sub nobody ;; select a subset of recent messages to be viewed (when there are more than what the agent is motivated to view) let latest-count-all 0 ;; count of all latest messages let recent-count-all 0 ;; count of all recent messages let latest-count-match 0 ;; count of latest messages that match member interest let recent-count-match 0 ;; count of recent messages that match member interest let latest-count-unmatch 0 ;; count of latest messages that do not match member interest let recent-count-unmatch 0 ;; count of recent messages that do not match member interest let latest-unmatch nobody ;; all latest messages that do not match member interest let recent-unmatch nobody ;; all recent messages that do not match member interest let latest-toview-match nobody ;; latest messages to be viewed that match member interest let recent-toview-match nobody ;; recent messages to be viewed that match member interest let latest-toview-unmatch nobody ;; latest messages to be viewed that do not match member interest let recent-toview-unmatch nobody ;; recent messages to be viewed that do not match member interest ;; with personalized view, only show messages that match member interests ifelse (ticks >= design-delay and personalize = "yes") [ set latest-toview messages with [age = 1 and member? topic self-intrlist] set recent-toview messages with [age <= readback and age > 1 and member? topic self-intrlist] set latest-count-all count latest-toview set recent-count-all count recent-toview ;; filter-precision indicates the precision of the personalized recommendation algorithm ;; when filter-precision < 1, only % of items match member interests ;; the following calculates and randomly select the number of matching and not-matching messages if (filter-precision < 1) [ set latest-count-match round (filter-precision * latest-count-all) set recent-count-match round (filter-precision * recent-count-all) if (latest-count-match < latest-count-all) [ ;; randomly choose number of matching messages set latest-toview-match n-of latest-count-match latest-toview set latest-unmatch messages with [age = 1 and member? topic self-intrlist = false] set latest-count-unmatch min ( list (count latest-unmatch) (latest-count-all - latest-count-match) ) ;; randomly choose number of not-matching messages set latest-toview-unmatch n-of latest-count-unmatch latest-unmatch set latest-toview messages with [member? self latest-toview-match or member? self latest-toview-unmatch] ] if (recent-count-match < recent-count-all) [ ;; randomly choose number of matching messages set recent-toview-match n-of recent-count-match recent-toview set recent-unmatch messages with [age <= readback and age > 1 and member? topic self-intrlist = false] set recent-count-unmatch min ( list (count recent-unmatch) (recent-count-all - recent-count-match) ) ;; randomly choose number of not-matching messages set recent-toview-unmatch n-of recent-count-unmatch recent-unmatch set recent-toview messages with [member? self recent-toview-match or member? self recent-toview-unmatch] ] ] ;; end of if (filter-precision < 1) ] ;; end of ifelse (ticks >= design-delay and personalize = "yes") [ ;; without personalized filtering, choose all messages from last tick or since last visit set latest-toview messages with [age = 1] set recent-toview messages with [age <= readback and age > 1] ] set latest-mess-count count latest-toview set recent-mess-count count recent-toview ;; after selecting the potential set of messages that an agent can view during the current tick ;; the following calculates exactly how many messages the agent is motivated to view ;; the number (1) is equal to or greater than 0, (2) is no more than all messages available for viewing, (3) is no more than 200 let mess-toview round min (list 200 ((max(list 0 p-benefits) / max-benefit) * (latest-mess-count + recent-mess-count))) if (mess-toview < 10 and latest-mess-count < 10) [ set mess-toview latest-mess-count ] ;; agents read message in reverse chronological order meaning they will first read the latest messages before going further back to recent messages ifelse (latest-mess-count >= mess-toview) [ if (latest-mess-count > 0) [ set mess-viewed (n-of mess-toview latest-toview) ] ] [ ifelse (recent-mess-count > 0) [ set recent-toview-sub n-of (mess-toview - latest-mess-count) recent-toview set mess-viewed messages with [member? self latest-toview or member? self recent-toview-sub] ] [ set mess-viewed latest-toview ] ] ;; questions are not informative unless they have replies if (mess-viewed != nobody) [ set mess-viewed-count count mess-viewed set mess-viewed-on (count mess-viewed with [topic > 0 and member? topic self-intrlist and question = 0] + count mess-viewed with [topic > 0 and member? topic self-intrlist and question = 1 and popularity > 0]) ] ;; let oldvalue 0 if (mess-viewed-count > 0) [ foreach values-from mess-viewed [topic] [ set oldvalue (item ? mess-viewed-topic) set mess-viewed-topic (replace-item ? mess-viewed-topic (oldvalue + 1)) ] ] if (ticks > 1000) [ ;; for debugging purpose output-type "latest-count= " + round latest-mess-count + " recent-count= " + round recent-mess-count + " mess-toview= " + round mess-toview + " viewed-count= " + round mess-viewed-count + " viewed-on= " + round mess-viewed-on output-show ticks ] ;;;;;; to calculate information benefit to self from accessing information, search cost ;; info-benefit is a marginally decreasing utility function of number of on-topic messages viewed let info-benefit max-benefit ifelse (mess-viewed-on <= 50) [ set info-benefit (0.15 * mess-viewed-on) ] [ if (mess-viewed-on <= 100) [ set info-benefit (0.05 * mess-viewed-on + 5) ] ] ;; search-cost simulate the cost of processing and reading information ;; it is proportional to the total number of messages viewed and modified by the number of on-topic messages ;; the greater number of on-topic messages, the lower the cost of having to search for these messages if (mess-viewed-on = 0) [set mess-viewed-on 1] set search-cost ( mess-viewed-count / 100) * (1 + min (list 1 (mess-viewed-count / mess-viewed-on - 1)) ) if (search-cost > (2 * max-benefit)) [ set search-cost (2 * max-benefit) ] ;; there are residula effects in benefits from accessing information, which combines the new experience and experience from last tick set info-b-self (info-b-self + (info-benefit - search-cost)) / 2 ;;;;;; to calculate benefits from having fun (instrinsic motivation) ;; benefit from fun is a function of agent's passion / interest in reading and posting online messages, modified by # messages viewed set fun-b-doing 0.5 * ( random-normal passion 1 ) set fun-b-doing min (list fun-b-doing (fun-b-doing * mess-viewed-count / 10)) ;;;;;; to calculate benefit from bonding ;; Members get more familiar with each other over time. Yet the effects of repeated interactions on familiarity is non-linear. ;; We assume a S-curve between the two: convex turning into concave at the transition point (=50 repeated interactions) and then level off. ;; We also assume that the maximum value of familiarity is 10 and half point is 5. ;; The two functions merge perfectly at the transition point (same value and same first-degree derivative) ;; Agents can derive bonding benefits from two things: repeated interactions with other agents and/or latest replies from from other agents let ties (max (list famsize lastresponses)) ;; see the calculate-familiarsize procedure for detai of how famsize is calculated let bond-b-old bond-b set bond-b max-benefit ifelse (ties <= 5) [ set bond-b ties ] [ if (ties <= 15) [ set bond-b (0.5 * ties + 2.5) ] ] set bond-b ((bond-b + bond-b-old) / 2) ;;;;;; to calculate benefit from identity ;; group norm is operationalized as the topics of messages a member reads ;; member feels greater connection to the group if message topics are more consistent with member interests let iden-tmp 0 ifelse (mess-viewed-count = 0) [ set iden-b iden-b ] [ ifelse (group-size >= ideal-size) [ set iden-tmp (1 * (count mess-viewed with [member? topic self-intrlist]) / mess-viewed-count ) set iden-b ( iden-b + iden-tmp) / 2 ] [ set iden-b (iden-b + 0) / 2 ] ] ;;;;;; to calculate benefit from willingness to help others and the community ;; agents will compensate if they think their contributions are unique or crucial to community success ;; agents will compensate if they think others are under contributing ;; we assume that the two processes take effects independently and are additive ;; which means members feel most obligated to compensate if they think they are unique and others under contributing let tocomp 0 set tocomp (tocomp + altruism) ;; According to the Collective Effort Model, agents are motivated to contribute to group outcomes only if they value the group, its members, or the tasks if (max (list fun-b-doing bond-b iden-b) >= 3) [ ifelse ( message-all < 100 ) [ ;; if the community is at crisis mood set tocomp ( tocomp + (5 * (100 - message-all) / 100) ) ] [ if ( message-self > (10 * message-all / close-size) ) ;; if the member thinks others are under-contributing [ set tocomp (tocomp + (min (list 3 (message-self * close-size / message-all )) )) ] ] ] ;; Dilution of responsiblity can happen when the community is larger than the ideal size, set to 15 for the current model ifelse (close-size > ideal-size) [ set info-tocomp min( list max-benefit (tocomp * (1 - (close-size - ideal-size) / (close-size + ideal-size))) ) ] [ set info-tocomp min(list max-benefit tocomp) ] ;;;;;; to calculate benefit from reputation (extrinsic motivation) ;; We assume that members who contributes 1/10 of the higest level of contribution receive repuation benefits ;; They don't get such benefits unless the community has more than 100 messages let goal-contribute (max values-from subjects [message-self] / 10) if (message-all > 100 and message-self >= goal-contribute) [ set reputation-b (min (list (max-benefit / 2) (0.1 * (message-self / goal-contribute)) )) ] if (history-part = 1) [ ;; record agent's first exposure to the community set first-viewed-count mess-viewed-count set first-viewed-topic mess-viewed-topic if (first-viewed-count > 0) [ set first-viewed-on (1 - (item 0 first-viewed-topic / first-viewed-count)) ] set first-info-b info-b-self set first-tocomp info-tocomp set first-fun-b fun-b-doing set first-bond-b bond-b set first-iden-b iden-b ] ;; motivation to contribute depends upon both benefit to self and willingness to help others but more upon willingness to help others set c-benefits-both ( (w-info * (0.33 * info-b-self + 0.67 * info-tocomp)) + (w-fun * (fun-b-doing + reputation-b) ) + (w-bond * bond-b) + (w-iden * iden-b) ) / (w-info + w-bond + w-fun + w-iden) ;; newcomers may not be allowed to post immediately after their registration let tmp-topic -1 let topic-list-sum 0 let topic-list-new n-values topic-breadth [ 0 ] let fromid subjectid-of self ;; subjectid id of the focal agent let toid -1 ;; subject id of the original poster let topost 0 ;; number of messages that the agent will post let topostnew 0 ;; number of new threads that the agent will post let toreply 0 ;; number of replies that the agent will post let prob-new 0.50 ;; probability of posting new threads (instead of replies) let newthread 0 ;; track the number of new threads the agent has posted for the current tick let newreply 0 ;; track the number of replies the agent has posted for the current tick let c-benefits (c-benefits-both - c-costs) ;; The following calculates the number of new threads and the number of replies ;; Research ahs shown that in technical communities, members change roles over time ;; first time posters have a high likelihood of posting new threads to ask a question (75%) ;; and oldtimers have a high likelihood of replying to existing threads to answer the question ;; members of all other three communities have an equal likelihood of doing both (50% and 50%) if (comm-type = "technical") [ if (history-cont < 1) [ set prob-new 0.75 ] if (message-self > (10 * message-all / close-size)) [ set prob-new 0.25 ] ;; experienced agents who have posted many ] ifelse (c-benefits >= comm-cost) [ set topost round (min (list random-gamma (c-benefits / comm-cost) 1 (10 * c-benefits / comm-cost))) set toreply round ( (1 - prob-new) * topost) set topostnew (topost - toreply) ] [ set topost 0 set topostnew 0 set toreply 0 ] let isquestion 0 ;; to post new threads if (topostnew > 0) [ ;; We assume that (1) oldtimers start new threads by conforming to group norms ;; (2) first-time poster only posts on-topic messages ;; when incubation N is greater than 0, it means newcomers can't post until they have participated for N times if (history-tick >= incubation) [ repeat topostnew [ ;; for agents who have posted before, the topic depends on self interest and messages viewed ifelse history-cont > 1 [ ifelse (mess-viewed-count > 0) [ set topic-list-new (map [?1 + ?2 / mess-viewed-count] self-interest mess-viewed-topic) ] [ set topic-list-new self-interest ] set topic-list-sum sum topic-list-new if (topic-list-sum > 0) [ set topic-list-new map [ ? / topic-list-sum ] topic-list-new ] ifelse (topic-list-sum = 0) [ set tmp-topic 0 ] [ let next 0 let prob-index random-float 1 let cumulative (cumulative + item next topic-list-new) while [next < topic-breadth and prob-index > cumulative] [ set next (next + 1) set cumulative (cumulative + item next topic-list-new) ] set tmp-topic next ] ;; agents of technical communites are more likely to ask questions ifelse (comm-type = "technical") [ ifelse (random-float 1 < 0.6) [set isquestion 1] [set isquestion 0] ] [ ifelse (random-float 1 < 0.4) [set isquestion 1] [set isquestion 0] ] ] ;; end of ifelse history-cont > 1 [ ;; otherwise, for newcomers, they choose a topic based on their interest and are more likely to ask questions ifelse (length self-intrlist = 0) [ set tmp-topic 0 ] [ set tmp-topic one-of self-intrlist ] ifelse (comm-type = "technical") [ ifelse (random-float 1 < 0.8) [set isquestion 1] [set isquestion 0] ] [ ifelse (random-float 1 < 0.6) [set isquestion 1] [set isquestion 0] ] ] ;; without community-level moderation, all messages get posted to the community if (ticks < design-delay or moderation = "no" or tmp-topic > 0) [ hatch-messages 1 [ set messageid max-mess-id set max-mess-id (max-mess-id + 1) set age 0 set thread -1 set parent -1 ;; a new thread set poster fromid set topic tmp-topic set question isquestion set popularity 0 ;; no response yet set createtick ticks set latesttick -1 set size 0.1 set hidden? not hidden? ] set newthread (newthread + 1) ;; one more message posted set newtopics (replace-item tmp-topic newtopics (item tmp-topic newtopics + 1)) set toid -2 ;; indicating the message is a new thread ] ] ;; end of repeat topostnew ] ;; end of if (history-part >= incubation) ] ;; end of if (topostnew > 0) ;; Agents consider three factors when deciding which messages to respond to: popularity, match of interest, and reciprocity ;; an index value is caculated for each potential candidate messages which is a weighted sum of the three factors if (toreply > 0) [ let scan-list n-values scan-scope [ nobody ] let parent-temp nobody ;; the message that the agent considers to respond to let reply-count2 0 ;; track the number of messages the agent has responded to let index-value 0 ;; the index value of candidate messages, higher index value means higher likelihood of response let interestmatch 0 ;; the degree to which a message matches the interests of the agent let reciprocity 0 ;; number of times the poster of the parent message has responded to the agent let howpopular 0 ;; the degree to which the parent message is popular in terms of attracting responses ;; if the agent has viewed more messages than the scan-scope, then select a random set ifelse (mess-viewed-count > scan-scope) [ set scan-list n-of scan-scope mess-viewed ] [ set scan-list mess-viewed ] if (scan-list != nobody) [ foreach values-from scan-list [messageid] [ set parent-temp (one-of messages with [messageid = ?]) ifelse (poster-of parent-temp = -1 or __in-link-from one-of subjects with [subjectid = poster-of parent-temp] = nobody) [ set reciprocity 0 ] [ ;; reciprocity equals to the number of times the poster of the parent message has responded to the agent set reciprocity (frequency-of __in-link-from one-of subjects with [subjectid = poster-of parent-temp]) ] ;; Popularity reflects the preferential attachment principle that people are attracted to messages that have many replies ;; popularity-of returns the number of responses the parent message has already received ifelse (thread-of parent-temp != -1) [ ;; the viewed message is a not thread set howpopular popularity-of parent-temp ] [ set howpopular max (list popularity-of parent-temp popularity-of one-of messages with [thread = thread-of parent-temp]) ] ;; set interestmatch to 1 if the topic of the message matches the interest of the agent ifelse (member? (topic-of parent-temp) self-intrlist) [ set interestmatch 1 ] [ set interestmatch 0 ] ;; howpopular normalized by average popularity (popular-mean) and reciprocity normalized by average strength of links (link-mean) ;; agents in different types of communities give slightly greater weight to some factors (mess-weight-delta) ;; technical - match of interest, health support - reciprocity, interest - reciprocity, political discussion - popularity and reciprocity if (comm-type = "technical") [ set index-value ( (1 + mess-weight-delta) * interestmatch + 1 * (howpopular / popular-mean) + 1 * (reciprocity / link-mean) + (question-of parent-temp / 10)) / (1 + 1 + 1 + 1 * mess-weight-delta) ] if (comm-type = "support") [ set index-value ( 1 * interestmatch + 1 * (howpopular / popular-mean) + (1 + mess-weight-delta) * (reciprocity / link-mean) + (question-of parent-temp / 10)) / (1 + 1 + 1 + mess-weight-delta ) ] if (comm-type = "interest" or comm-type = "movielens") [ set index-value ( 1 * interestmatch + 1 * (howpopular / popular-mean) + (1 + mess-weight-delta) * (reciprocity / link-mean) + (question-of parent-temp / 10)) / (1 + 1 + 1 + mess-weight-delta ) ] if (comm-type = "political") [ set index-value ( 1 * interestmatch + (1 + mess-weight-delta) * (howpopular / popular-mean) + (1 + 1.5 * mess-weight-delta) * (reciprocity / link-mean) + (question-of parent-temp / 10)) / (1 + 1 + 1 + mess-weight-delta + 1.5 * mess-weight-delta) ] set scanindex-of parent-temp index-value ] ;; The agent then decides whether to post replies, which messages to reply to, and on what topic let parent-mess nobody ;; parent messages the agent will choose to reply to let parent-topic -1 ;; topic of the parent message the agent will choose to reply to let parent-thread -1 ;; id of the original thread of the parent message let adjustment 0 ;; (see below for detail) ;; scan-list includes a list of messages the agent has viewed ;; first sort the messages based on their index value - higher the value, greater likelihood to reply to set scan-list sort-by [scanindex-of ?1 > scanindex-of ?2] scan-list while [reply-count2 < toreply and reply-count2 < (length scan-list) and (item reply-count2 scan-list) != nobody ] [ set parent-mess (item reply-count2 scan-list) set parent-topic topic-of parent-mess ifelse (thread-of parent-mess = -1) [ set parent-thread messageid-of parent-mess ] [ set parent-thread thread-of parent-mess ] ;; if a message is not a thread then also increase the popularity of the original thread by 1 ;; set latesttick of both parent message and thread to the current tick ;; latesttick indicates the tick when a message received the latest response set popularity-of parent-mess (popularity-of parent-mess + 1) set latesttick-of parent-mess ticks ;; track the number of responses the poster receives for the current tick ;; which will be used to calculate bond benefits for the next tick if (poster-of parent-mess != -1) [ ;; set nowresponses-of (one-of subjects with [subjectid = poster-of parent-mess]) (nowresponses-of (one-of subjects with [subjectid = poster-of parent-mess]) + 1) ] ;; adjustment is the average strength of the two directional links between the agent and the poster if (poster-of parent-mess != -1 and __in-link-from one-of subjects with [subjectid = poster-of parent-mess] != nobody and __out-link-to one-of subjects with [subjectid = poster-of parent-mess] != nobody) [ set adjustment mean (list frequency-of __in-link-from one-of subjects with [subjectid = poster-of parent-mess] frequency-of __out-link-to one-of subjects with [subjectid = poster-of parent-mess]) ] ;; in non-technical communities, agents with repeated interactions are more likely to engage in off-topic discussion ifelse (comm-type != "technical" and random-float 1 < (adjustment / 10)) [ set tmp-topic 0 ;; response message is off-topic ] [ set tmp-topic parent-topic ] ;; topic of the response message is the same as the topic of the parent message ;; post a response to the parent message unless there is community-level moderation and the message is off-topic if (ticks < design-delay or moderation = "no" or tmp-topic > 0) [ hatch-messages 1 [ set messageid max-mess-id set max-mess-id (max-mess-id + 1) set age 0 set thread parent-thread set parent messageid-of parent-mess set poster fromid set topic tmp-topic ifelse (random-float 1 < 0.2) [set question 1] [set question 0] set popularity 0 set createtick ticks set latesttick -1 set size 0.1 set hidden? not hidden? ] set newreply (newreply + 1) ; set newtopics (replace-item tmp-topic newtopics (item tmp-topic newtopics + 1)) set toid poster-of parent-mess ;; we assume that (1) off-topic messages are a form of self-disclosure that leads to stronger bonding ;; (2) agents with greater similarity in interests build stronger bonding when they interact let delta 1 if (tmp-topic = 0) [set delta (delta + 1)] let priorfreq 0 let towhom nobody let other-interest 0 let sim-delta 0 let interest-overlap n-values topic-breadth [0] ;; seed messages have no poster and subjects can respond to self if (toid != -1 and toid != fromid) [ set towhom one-of subjects with [subjectid = poster-of parent-mess] set other-interest (interest-of towhom) ;; interest of the original poster ;; sim-delta measures similarity between two agents ;; it ranges between 0 and 1 depending on overlap of agents' interests set interest-overlap (map [?1 + ?2] self-interest other-interest) set sim-delta ( length (filter [? > 1] interest-overlap) / topic-breadth ) ;; if there is already a link between the two agents then increase its frequency ;; otherwise create a new link from the agent to the poster of the parent message ifelse (__out-link-neighbor? towhom) [ ;; with existing link between agent and poster set priorfreq (frequency-of __out-link-to towhom) set (frequency-of __out-link-to towhom ) (priorfreq + (delta + sim-delta)) set getold-of __out-link-to towhom 0 ] [ set priorfreq 0 ;; no existing link between agent and poster __create-link-to towhom [] set (linkid-of __out-link-to towhom) max-link-id set max-link-id (max-link-id + 1) set (linkage-of __out-link-to towhom) 0 set (getold-of __out-link-to towhom) 0 ;; link refreshed set frequency-of __out-link-to towhom (delta + sim-delta) set hidden?-of __out-link-to towhom not hidden? ] if (output-interact = true) [ ;; output new messages posted by members file-open "interact.txt" file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + fromid + " " + toid + " " + (max-mess-id - 1) + " " + tmp-topic + " " + sim-delta + " " + priorfreq + " " + reciprocity + " " file-print howpopular file-close ] ] ] ;; end of if (ticks < design-delay) set reply-count2 (reply-count2 + 1) ] ;; end of while reply-count2 ] ;; end of if (scan-list != nobody) ] ;; end of if (c-benefits > c-costs) let posted (newthread + newreply) if (posted) > 0 [ ;; member posted at least one message set message-self (message-self + posted) ;; agent message contribution increased by 1 set history-cont (history-cont + 1) ;; agent hitory of contributing increased by 1 set tick-conts (tick-conts + 1) ;; total number of contributors in the current tick increased by 1 set tick-posts (tick-posts + posted) ;; total number of posts increased by posted set tick-links (tick-links + newreply) ;; total number of replies increased to newreply set tick-threads (tick-threads + newthread) ;; total number of threads icnreased by newthread set latestcont ticks ;; latest tick at which a member posted updated if (islurker = 1) [ set islurker 0 set firstcont ticks set newposters (newposters + 1) ] ] ;; output member benefits every 50th ticks if (output-benefit = true and (ticks + 1) mod 50 = 0) [ file-open "benefit.txt" file-type run-number + " " + comm-type + " " + ticks + " " + offtopic-interest + " " + filter-precision + " " + comm-cost + " " + max-messages + " " + topic-breadth + " " + moderation + " " + personalize + " " + subjectid + " " + createdate + " " + firstpart + " " + firstcont + " " + latestpart + " " + latestcont + " " + (precision info-benefit 3) + " " + (precision search-cost 3) + " " + (precision info-b-self 3) + " " + (precision info-tocomp 3) + " " + (precision fun-b-doing 3) + " " + (precision reputation-b 3) + " " + (precision bond-b 3) + " " + (precision iden-b 3) + " " + (precision p-benefits 3) + " " + (precision p-costs 3) + " " + (precision c-benefits-both 3) + " " + (precision c-costs 3) + " " + newthread + " " + newreply + " " file-print posted file-close ] if (posted > 1 and ticks > 1000) [ output-type (mess-viewed-count + " " + mess-viewed-on + " " + (precision info-benefit 2) + " " + (precision search-cost 2) + " " + (precision info-b-self 2) + " " + (precision info-tocomp 2) + " " + (precision fun-b-doing 2) + " " + (precision reputation-b 2) + " " + (precision bond-b 2) + " " + (precision iden-b 2)) output-show ticks output-type ((precision p-benefits 2) + " " + (precision c-benefits-both 2)) output-show ticks ] ] ;; end of ifelse (p-benefits >= p-costs) [ ;; if the agent didn't participate, then increase inactive period by 1 set inactive (inactive + 1) ] set history-tick (history-tick + 1) ;; agent history since joining the community increased by 1 end ;; Calculate the number of other agents the focal agent has had repeated interactions ;; famsize is used to calculate experienced benefit from bonding ;; An agent is considered to having had repeated interactions and therefore close relatinships ;; with the focal agent if they have corresponded at least twice (both directions of interaction) to calculate-familiarsize let both-circle 0 let delta-min 0 ;; minimum of in and outdegree if (count __in-link-neighbors with [membership = 1] > 0) [ ;; if there is anyone who has responded to the agent foreach values-from __in-link-neighbors with [membership = 1] [subjectid] [ if (__in-link-from one-of subjects with [subjectid = ?] != nobody) and (__out-link-to one-of subjects with [subjectid = ?] != nobody ) [ ;; only count those with reciprocical ties set delta-min min ( list frequency-of __in-link-from one-of subjects with [subjectid = ?] frequency-of __out-link-to one-of subjects with [subjectid = ?] ) if (delta-min >= 2) [ set both-circle (both-circle + 1) ] ] ] ] set famsize both-circle end to setup-plots set-current-plot "Member Statistics" set-current-plot "Member Entry and Exit" clear-plot end to update-plots set-current-plot "Member Statistics" set-current-plot-pen "Member" ;; track number of active members for each tick plot count subjects with [membership = 1] set-current-plot-pen "Lurker" ;; track number of participants for each tick plot tick-parts set-current-plot-pen "Poster" ;; track number of contributors for each tick plot tick-conts set-current-plot-pen "Post" ;; track number of new posts for each tick plot count messages with [age = 1] set-current-plot "Member Entry and Exit" set-current-plot-pen "Newcomer" ;; track number of newcomers plot newcomer set-current-plot-pen "NewPoster" ;; track number of new posters plot newposters set-current-plot-pen "LurkerExit" ;; track number of new lurkers who join but have not posted plot lurkleave set-current-plot-pen "PosterExit" ;; track number of members who leave the community at the tick plot postleave end ; add model procedures here @#$#@#$#@ GRAPHICS-WINDOW 599 21 1147 535 19 17 13.8 1 10 1 1 1 0 1 1 1 -19 19 -17 17 CC-WINDOW 5 555 1156 650 Command Center 0 BUTTON 35 18 98 51 NIL setup NIL 1 T OBSERVER T NIL BUTTON 113 17 176 50 NIL go T 1 T OBSERVER T NIL PLOT 21 246 562 541 Member Statistics Time Count 0.0 10.0 0.0 10.0 true true PENS "Member" 1.0 0 -7500403 true "Lurker" 1.0 0 -13345367 true "Poster" 1.0 0 -2674135 true "Post" 1.0 0 -16777216 true SLIDER 21 58 193 91 initial-members initial-members 0 1000 180 5 1 NIL SLIDER 21 131 196 164 run-time run-time 0 5000 300 50 1 NIL SLIDER 21 95 194 128 initial-messages initial-messages 0 500 30 1 1 NIL CHOOSER 39 168 177 213 comm-type comm-type "technical" "interest" "support" "political" "movielens" 0 PLOT 211 10 557 239 Member Entry and Exit NIL NIL 0.0 10.0 0.0 10.0 true true PENS "Newcomer" 1.0 0 -10899396 true "NewPoster" 1.0 0 -955883 true "LurkerExit" 1.0 0 -13345367 true "PosterExit" 1.0 0 -16777216 true @#$#@#$#@ WHAT IS IT? ----------- This model is an agent-based model that simulates member motivation and contribution in a conversation-based online community such as UseNet groups or web forums. Individual agents imitate members in an online community and can make decisions to read and post messages based on perceived benefits and costs of doing so. It can be used to run virtual experiments to develop theories about individual behaviors and social dynamics in online communities and to inform the design of real-life online communities. HOW IT WORKS ------------ Each tick simulates a day in real life. At each tick, community members decide whether to participate by reading messages and whether to contribute by posting messages. They consider four types of benefits from receiving information, sharing information, social connections with the community and its members, fun and reputation. They also incur costs in reading and posting messages. A member reads and/or posts messages when (expected) benefits from reading and/or posting messages exceed costs of reading and/or posting messages. Members who remain inactive for a long period of time are regarded as having left the community. HOW TO USE IT ------------- Use the sliders initial-member, initial-message, and run-time to specify the initial condition of the community. Use the chooser comm-type to specify the type of the community: technical, interest, support, and political. Members of different types of communities diff in their motivations. For instance, members of technical communities such as a JAVA developer group care more about finding information about JAVA development than making friends whereas members of a health support group care about both finding information and giving and receiving social support. Click the SETUP button to create a virtual community. Click GO to run the simulation. THINGS TO NOTICE ---------------- - Watch how members enter and exit the community. - Watch what happens in the Member Statistics Plot. - Watch what happens in the Member Entry and Exit Plot. The program also outputs statistics to a text file for further analysis. For example, you can track member composition in terms of history and interests, member entry and exit and visit frequency, various type of benefits individual members experience over time, or the number of messages posted by members over time. THINGS TO TRY ------------- - Try to change the number of initial members and see what happens. - Try to change the type of community and see what happens. Or you can use the Behavior Space under "Tools" to vary pany parameters in the model to run virtual experiments. We have included the experiment we ran for the Human-Computer Interaction paper as an example. Vary variables as follows: ["initial-member" 30] ["initial-message" 30] ["run-time" 250] ["comm-type" "interest"] ["moderation" "no" "yes"] ["personalize" "no" "yes"] ["topic-breadth" 2 6 10] ["offtopic-interest" 0.1 0.3 0.5] ["filter-precision" 1 0.8 0.6] Repetitions: 5 Measure runs using these reporters: run-number count subjects count subjects with [membership = 1] count subjects with [message-self > 0] count messages count messages with [thread = -1] EXTENDING THE MODEL ------------------- The model can be extended in many ways. It can be extended to simulate other types of online communities. Currently, it is built to simulate conversation-based communities and you can add new actions to simulate production-based communities like Wikipedia. That requies the creation of new objects such as articles or user profiles and the relationships between members and these objects. It can be extended to incorporate more social science theories or features of online communities. Currently, we draw on a selective set of theories such as value expectancy theory, Collective Effort Models, information overload, group identity and interpersonal bonds, reciprocity, etc. Insights from other theories such as public goods, critical mass, task interdependence, network externality and evolution can be incorporated to enrich the model. Or it can be extended by simulating the working of new features such as leader board, subgroups, user ratings of messages, etc. CREDITS AND REFERENCES ---------------------- This model is authoried by Yuqing Ren at Univeristy of Minnesota and Robert E. Kraut at Carnegie Mellon University. You can find a detailed description in our paper forthcoming at Human-Computer Interaction. To refer to this model in academic publications, please use: Ren, Y. & Kraut, R. forthcoming. Agent-Based Modeling to Inform Online Community Design: Impact of Topical Breadth, Message Volume, and Discussion Moderation on Member Commitment and Contribution. Human-Computer Interaction. @#$#@#$#@ default true 0 Polygon -7500403 true true 150 5 40 250 150 205 260 250 link true 0 Line -7500403 true 150 0 150 300 link direction true 0 Line -7500403 true 150 150 30 225 Line -7500403 true 150 150 270 225 airplane true 0 Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15 arrow true 0 Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150 box false 0 Polygon -7500403 true true 150 285 285 225 285 75 150 135 Polygon -7500403 true true 150 135 15 75 150 15 285 75 Polygon -7500403 true true 15 75 15 225 150 285 150 135 Line -16777216 false 150 285 150 135 Line -16777216 false 150 135 15 75 Line -16777216 false 150 135 285 75 bug true 0 Circle -7500403 true true 96 182 108 Circle -7500403 true true 110 127 80 Circle -7500403 true true 110 75 80 Line -7500403 true 150 100 80 30 Line -7500403 true 150 100 220 30 butterfly true 0 Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240 Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240 Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163 Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165 Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225 Circle -16777216 true false 135 90 30 Line -16777216 false 150 105 195 60 Line -16777216 false 150 105 105 60 car false 0 Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180 Circle -16777216 true false 180 180 90 Circle -16777216 true false 30 180 90 Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89 Circle -7500403 true true 47 195 58 Circle -7500403 true true 195 195 58 circle false 0 Circle -7500403 true true 0 0 300 circle 2 false 0 Circle -7500403 true true 0 0 300 Circle -16777216 true false 30 30 240 cow false 0 Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167 Polygon -7500403 true true 73 210 86 251 62 249 48 208 Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123 cylinder false 0 Circle -7500403 true true 0 0 300 dot false 0 Circle -7500403 true true 90 90 120 face happy false 0 Circle -7500403 true true 8 8 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240 face neutral false 0 Circle -7500403 true true 8 7 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Rectangle -16777216 true false 60 195 240 225 face sad false 0 Circle -7500403 true true 8 8 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183 fish false 0 Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166 Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165 Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60 Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166 Circle -16777216 true false 215 106 30 flag false 0 Rectangle -7500403 true true 60 15 75 300 Polygon -7500403 true true 90 150 270 90 90 30 Line -7500403 true 75 135 90 135 Line -7500403 true 75 45 90 45 flower false 0 Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135 Circle -7500403 true true 85 132 38 Circle -7500403 true true 130 147 38 Circle -7500403 true true 192 85 38 Circle -7500403 true true 85 40 38 Circle -7500403 true true 177 40 38 Circle -7500403 true true 177 132 38 Circle -7500403 true true 70 85 38 Circle -7500403 true true 130 25 38 Circle -7500403 true true 96 51 108 Circle -16777216 true false 113 68 74 Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218 Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240 house false 0 Rectangle -7500403 true true 45 120 255 285 Rectangle -16777216 true false 120 210 180 285 Polygon -7500403 true true 15 120 150 15 285 120 Line -16777216 false 30 120 270 120 leaf false 0 Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195 Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195 line true 0 Line -7500403 true 150 0 150 300 line-half true 0 Line -7500403 true 150 0 150 150 pentagon false 0 Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120 person false 0 Circle -7500403 true true 110 5 80 Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90 Rectangle -7500403 true true 127 79 172 94 Polygon -7500403 true true 195 90 240 150 225 180 165 105 Polygon -7500403 true true 105 90 60 150 75 180 135 105 plant false 0 Rectangle -7500403 true true 135 90 165 300 Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285 Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285 Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210 Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135 Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135 Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60 Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90 square false 0 Rectangle -7500403 true true 30 30 270 270 square 2 false 0 Rectangle -7500403 true true 30 30 270 270 Rectangle -16777216 true false 60 60 240 240 star false 0 Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108 target false 0 Circle -7500403 true true 0 0 300 Circle -16777216 true false 30 30 240 Circle -7500403 true true 60 60 180 Circle -16777216 true false 90 90 120 Circle -7500403 true true 120 120 60 tree false 0 Circle -7500403 true true 118 3 94 Rectangle -6459832 true false 120 195 180 300 Circle -7500403 true true 65 21 108 Circle -7500403 true true 116 41 127 Circle -7500403 true true 45 90 120 Circle -7500403 true true 104 74 152 triangle false 0 Polygon -7500403 true true 150 30 15 255 285 255 triangle 2 false 0 Polygon -7500403 true true 150 30 15 255 285 255 Polygon -16777216 true false 151 99 225 223 75 224 truck false 0 Rectangle -7500403 true true 4 45 195 187 Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194 Rectangle -1 true false 195 60 195 105 Polygon -16777216 true false 238 112 252 141 219 141 218 112 Circle -16777216 true false 234 174 42 Rectangle -7500403 true true 181 185 214 194 Circle -16777216 true false 144 174 42 Circle -16777216 true false 24 174 42 Circle -7500403 false true 24 174 42 Circle -7500403 false true 144 174 42 Circle -7500403 false true 234 174 42 turtle true 0 Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210 Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105 Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105 Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87 Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210 Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99 wheel false 0 Circle -7500403 true true 3 3 294 Circle -16777216 true false 30 30 240 Line -7500403 true 150 285 150 15 Line -7500403 true 15 150 285 150 Circle -7500403 true true 120 120 60 Line -7500403 true 216 40 79 269 Line -7500403 true 40 84 269 221 Line -7500403 true 40 216 269 79 Line -7500403 true 84 40 221 269 x false 0 Polygon -7500403 true true 270 75 225 30 30 225 75 270 Polygon -7500403 true true 30 75 75 30 270 225 225 270 @#$#@#$#@ NetLogo 3.1.5 @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ setup go run-number count subjects count subjects with [membership = 1] count subjects with [message-self > 0] count messages count messages with [thread = -1] @#$#@#$#@