AdelLahlou-FeedbackConstraintSatisfaction-EECS372
Model was written in NetLogo 6.0-M5
•
Viewed 439 times
•
Downloaded 27 times
•
Run 0 times
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
Info tab cannot be displayed because of an encoding error
Comments and Questions
Please start the discussion about this model!
(You'll first need to log in.)
Click to Run Model
;; Author: Adel Lahlou ;; Modeling Software development extensions [array table palette] globals [number-of-consumers number-of-workers number-of-managers product-id-sequence ideal-product market-product current-product no-product feedback-choices energy-recovery now-and-then-length general-consumer-type consumers-satisfaction-sensitivity upgrade-difference feedback-round features-round quality-round energy-round benefit-cost-round total-benefit] ;; ideal-product is the current goal -> what the market currently wants ;; market-product is what is currently buyable ;; current-product is what is currently developed by the firm breed [workers worker] breed [managers manager] breed [consumers consumer] breed [products product] breed [features feature] breed [feedback a-feedback] ;; nat turtles-own [age] ;; nat products-own [id] ;; nat nat number features-own [fid product-id quality] ;; feature number feedback-own [bad-feature feedback-type quality addressed?] ;; number number (listof features) (listof features) workers-own [energy productivity newly-assigned assigned worked-on] ;; number number (listof features) number managers-own [energy productivity focused-features-ids worked-on] ;; number number product string number number consumers-own [energy productivity owned-product bought-at-age consumer-type satisfaction ] ;; think about using vision and communication skill ;;;;;;;;;;;;;;; SETUP CODE ;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; observer -> void: creates the initial ideal product and its features. It then creates workers ;; and managers. Lastly it creates consumers. to setup clear-all ask patches [ set pcolor 3 ] initialize-globals create-workforce create-market color-turtles display-agents reset-ticks end to display-agents ;; setup workers, managers, and consumers ask workers [set shape "person"] ask managers [set size 1.3 set shape "person"] ask consumers [set shape "house"] let total-workers (count workers + count managers) let worker-part (count workers / total-workers) let managers-part (count managers / total-workers) let midway (max-pycor / 2) let y-divide (midway * worker-part) grid-layout workers 0 midway 0 y-divide 5 grid-layout managers 0 midway (y-divide + 0.5) (midway + 1) 5 grid-layout consumers (midway + 0.5) (max-pxcor + 1) 0 (midway + 1) 5 ;;lays out the products at the top ask products [ set shape "star" set size 1.5] ;; layout features beneath it set-feature-shapes layout-features ;grid-layout features 0.2 (max-pxcor + 1) (midway + 2) (max-pycor - 2) 16 end to layout-features let ideal-features (sort-on [fid] features-of ideal-product) let current-features (sort-on [fid] current-extra-features) let all-features (join-lists ideal-features current-features) let total-features (length current-features + length ideal-features) let midway (max-pycor / 2) grid-layout-list (sort-on [id] products) 0 (max-pxcor + 1) (max-pycor - 1) (max-pycor - 0.2) 16 grid-layout-list all-features 0.2 (max-pxcor + 1) (midway + 1.8) (max-pycor - 2) 16 end ;; observer -> void: creates an ideal product (the goal) and initializes the the market-product and current-product ;; to no-product global. Any other initial variables are initialized from parameters to initialize-globals ;; set variables from parameters ; set tech-forefront initial-tech set consumers-satisfaction-sensitivity 30 set now-and-then-length 50 set upgrade-difference 20 set general-consumer-type "early-adopter" set energy-recovery 15 set number-of-consumers initial-number-of-consumers set number-of-workers initial-number-of-workers set number-of-managers initial-number-of-managers set feedback-choices ["missing" "quality" "superfluous"] set energy-round 1 ;; generate initial products set product-id-sequence 0 ;; creates a no-product global. This is because this is more correct than NOBODY ;; and prevents issues from having NOBODY let no-product-id generate-product-id create-products 1 [ set id no-product-id set age 0 ] ;; generate the current ideal product set ideal-product generate-ideal-product ;; no-product currently exists in development or in market set no-product one-of products with [id = no-product-id] set market-product no-product ; set current-product no-product let current-pid generate-product-id create-products 1 [ set id current-pid set age 0 ] set current-product one-of products with [id = current-pid] end ;; observer -> void: creates workers and managers to create-workforce create-workers number-of-workers [ set energy max-energy set productivity generate-productivity set newly-assigned [] set assigned [] set worked-on [] ;; they haven't worked on any features yet ] create-managers number-of-managers [ set energy max-energy set productivity generate-productivity set focused-features-ids [] set worked-on [] ;set vision 0 ] end ;; observer -> void to create-market ifelse general-consumer-type = "mix" [ let consumer-types ["early-adopter" "now-and-then" "upgrade-only" "upgrade-now-and-then" "patient"] create-consumers number-of-consumers [ set energy max-energy set productivity generate-productivity set owned-product current-product ;; everyone currently owns no product set consumer-type one-of consumer-types ;set communication-skill 0 ]] ;; create consumers of one type [create-consumers number-of-consumers [ set energy max-energy set productivity generate-productivity set owned-product no-product ;; everyone currently owns no product set consumer-type general-consumer-type ;set communication-skill 0 ]] end ;; observer -> product ;; Possible Improvement: make is so later this can be used to make new ideal products "moving target" to-report generate-ideal-product let a-product-id generate-product-id let used-ids [] let potential-feature-id generate-feature-id ;; creates ideal-number-of-features unique features with max quality create-features ideal-number-of-features [ set product-id a-product-id set quality 0 set age 0 set fid generate-new-id used-ids set used-ids lput fid used-ids ] create-products 1 [ set id a-product-id set age 0 ] report one-of products with [id = a-product-id] end ;;;;;;;;;;;;;; END SETUP CODE ;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;; GO CODE ;;;;;;;;;;;;;;;;;;;;;;; ;; observer -> void: to go ;; consumers buy products and give feedback let ideal-quality product-quality ideal-product let market-quality product-quality market-product let current-quality product-quality current-product let ideal-features features-of ideal-product let ideal-features-ids [fid] of ideal-features ;; have consumers buy products and give feedback ask consumers [ let owned-quality product-quality owned-product buy-product owned-quality ideal-quality market-quality current-quality give-feedback ideal-features ideal-features-ids ] ;; managers selectively listen to some of the feedback and ;; then assign work to workers based off their work history let occurrences calculate-feedback-occurrences ;; [[id occurences] ...] let oldest-feedback calculate-feedback-oldest ;; [[id age] ...] let occurrences-sorted sort-by [pair-greater ? ? 1] table:to-list occurrences ;let occurrences-features-list map [sentence (features with [fid = first ?]) (item 1 ?)] occurrences-sorted let oldest-feedback-list sort-on [age] feedback let average-team-amt ceiling (count workers / count managers) ask managers [ ifelse energy >= manager-energy-cost [ listen-to-feedback occurrences-sorted oldest-feedback-list manage-workers average-team-amt set energy (energy - manager-energy-cost) set energy-round (energy-round + manager-energy-cost) ] [set energy max (sentence max-energy (energy + energy-recovery))] ] ask workers [ do-work ] ;; product publishing is currently disabled ;; might not always replace the market product with the current product if publish-project? [ publish-product if retention-issue? [replace-workers] ] ask turtles [ do-age ] update-display ;; work around to prevent divide by zero if energy-round = 0 [set energy-round 1] tick reset-round end to update-display set-feature-shapes color-turtles layout-features end to-report publish-project? report true end to replace-workers let num-layoffs count workers * (1 - retention-rate) ;; reset everything as if they were ask n-of num-layoffs workers [ set energy max-energy set productivity generate-productivity set assigned [] set worked-on [] set age 0 ] end ;; consumer -> void: The consumer inspects the four relevant products: owned, ideal, market, current. ;; Based on their ctype, they act differently to buy-product [owned-quality ideal-quality market-quality current-quality] ;; these consumers always buy the newest product, better or worse if consumer-type = "early-adopter" [ let owned-id [id] of owned-product let market-id [id] of market-product if owned-id != market-id [ buy-market-product ] ] ;; these consumers buy a new product every now and then, no matter the quality ;; they aim for "new to them" if consumer-type = "now-and-then" [ let owned-age [age] of owned-product let own-length (owned-age - bought-at-age) if nearish own-length now-and-then-length [ buy-market-product ] ] ;; these consumers vigorously review new products and will always buy the latest and greatest ;; if they are better enough to be called an upgrade if consumer-type = "upgrade-only" [ if market-quality >= (owned-quality + upgrade-difference) [ buy-market-product ] ] ;; these consumers only try to upgrade every now and then ;; and only buy if they are good enough to be called an upgrade if consumer-type = "upgrade-now-and-then" [ if market-quality >= (owned-quality + upgrade-difference) [ let owned-age [age] of owned-product let own-length (owned-age - bought-at-age) if nearish own-length now-and-then-length [ buy-market-product ] ] ] ;; these consumers won't buy a new model if they know that an upgraded product ;; is currently developed, and will only buy if it's an upgrade. Keeps waiting ;; for things just around the corner if consumer-type = "patient" [ ;; it's an upgrade if market-quality >= (owned-quality + upgrade-difference) [ ;; make sure that the next upgrade isn't already almost out if (market-quality + upgrade-difference) <= current-quality [ buy-market-product ] ] ] end ;; consumer -> void: If they have the energy, a consumer inspects there currently owned product. ;; They have a sense that let's them report one of three errors: a feature is missing, a feature ;; is superfluous, or a feature is too low-quality. They determine which one they will do randomly. to give-feedback [ideal-features ideal-features-ids] ;; only do if have enough energy if energy < feedback-energy-cost [set energy min (sentence max-energy (energy + energy-recovery)) stop] if random 100 >= feedback-chance [set energy min (sentence max-energy (energy + energy-recovery)) stop ] let complaint-feature NOBODY let a-feedback-type one-of feedback-choices let owned-features features-of owned-product if not any? owned-features [ set a-feedback-type "missing" ] ;; chooses one of the superfluous features if a-feedback-type = "superfluous" [ set complaint-feature [fid] of one-of owned-features with [not member? fid ideal-features-ids] if complaint-feature = NOBODY [ set a-feedback-type "quality"] ] ;; choosest one of the poorest quality features if a-feedback-type = "quality" [ ifelse count owned-features > 3 [set complaint-feature [fid] of one-of min-n-of 3 owned-features [quality]] [set complaint-feature [fid] of one-of owned-features] ] ;; feature is missing from the product they own if a-feedback-type = "missing" [ ifelse random 100 < feedback-accuracy [ let owned-features-ids [fid] of owned-features let disjoint-features ideal-features with [not member? fid owned-features-ids] if any? disjoint-features [ set complaint-feature [fid] of one-of disjoint-features] ] [ set complaint-feature generate-feature-id ] ] if complaint-feature != NOBODY [ hatch-feedback 1 [ set bad-feature complaint-feature set feedback-type a-feedback-type set quality [productivity] of myself set addressed? false set age 0 hide-turtle ] set feedback-round (feedback-round + 1) set energy (energy - feedback-energy-cost) set energy-round (energy-round + feedback-energy-cost) ] end ;; observer void -> hashtable[number]natural to-report calculate-feedback-occurrences let occurrences table:make ask feedback with [addressed? = false] [ let a-fid bad-feature ifelse table:has-key? occurrences a-fid [ let cur-occur table:get occurrences a-fid table:put occurrences a-fid (cur-occur + 1)] [ table:put occurrences a-fid 1 ] ] report occurrences end ;; observer void -> hashtable[number]natural to-report calculate-feedback-oldest let oldest-feedback table:make ask feedback with [addressed? = false] [ let a-fid bad-feature ifelse table:has-key? oldest-feedback a-fid [ let cur-oldest-age table:get oldest-feedback a-fid if age > cur-oldest-age [ table:put oldest-feedback a-fid age]] [ table:put oldest-feedback a-fid age] ] report oldest-feedback end to-report compare-age [t1 t2] let t1-age first [age] of t1 let t2-age first [age] of t2 report t1-age > t2-age end ;; manager -> void: The manager chooses some feedback to act on. The manager can do this by considering ;; which features have the most feedback, the oldest feedback, feedback type, number of workers who've worked on it, ;; and then considering quality. ;; idea of weighting -> managers choose based on how old the feedback is, number of occurrences, and what they've worked on before to listen-to-feedback [features-occurrences oldest-feedback] let occur-amt 10 let age-amt 3 ;; select some of the most highest occuring features. if length features-occurrences < occur-amt [set occur-amt length features-occurrences] let potentials map first sublist features-occurrences 0 occur-amt ;; choose a few of the oldest feedback among a random if age-amt > length oldest-feedback [set age-amt length oldest-feedback] let chosen-old map [[bad-feature] of ?] sublist oldest-feedback 0 age-amt ; set potentials map first (sublist ((sort-by [compare-age first ? first ?] features-occurrences) 0 age-amt)) set potentials join-lists potentials chosen-old set potentials join-lists potentials focused-features-ids ;; join potentials with recently worked on let choice-amt projects-per-manager if choice-amt > length potentials [set choice-amt length potentials] set focused-features-ids n-of choice-amt potentials ;foreach focused-features-ids [ ask feedback with [[fid] of bad-feature = ?] [set addressed? true ] ] end to-report count-occurrences [a-list] let occurrences table:make foreach (sort-by < a-list) [ ifelse table:has-key? occurrences ? [ let cur-occur table:get occurrences ? table:put occurrences ? (cur-occur + 1)] [ table:put occurrences ? 1 ] ] report occurrences end to-report join-lists [l1 l2] foreach l2 [set l1 lput ? l1] report l1 end ;; manager -> void: ;; TODO: make how workers incorporate the ways to choose features from software development lifecycle ;; TODO: consider whether assigned work should be unique to manage-workers [average-team-amt] foreach focused-features-ids [ let focused-id ? ;; first grab some people knowledgeable about the problem let legacies (sort-on [who] (workers with [worked-on-id? ?])) if length legacies >= average-team-amt [set legacies n-of average-team-amt legacies] ;; and grab people with little assigned work let least-busy sublist (sort-on [length assigned] workers) 0 average-team-amt ;; make final list let contributors n-of average-team-amt join-lists legacies least-busy foreach contributors [ ask ? [set newly-assigned lput focused-id newly-assigned ]] ] end ;; worker -> void: chooses from assigned, performs a certain amount of work on it ;; can incorporate the ways to do work from software development lifecycle ;; look into making a request breed, which can have a priority associated with it to do-work ifelse energy > worker-energy-cost [ let usable-energy (worker-energy-cost * productivity) let worked-on-count count-occurrences worked-on ;; checks if there is assigned work to do ifelse not empty? newly-assigned or not empty? assigned [ ;; chance to continue old work that they've been asked to continue let legacy-work filter [member? ? worked-on] assigned ;; chance to do most recent work ;; use newly-assigned ;; chance to do most asked for work let id-occurrences-table count-occurrences assigned let sorted-occurrences map first (sort-by [pair-greater ?1 ?2 1] (table:to-list id-occurrences-table)) let grab-amt 3 if length sorted-occurrences > grab-amt [set sorted-occurrences sublist sorted-occurrences 0 grab-amt] let potential join-lists sorted-occurrences (join-lists legacy-work newly-assigned) ;; unreachable, this can't happen, since we check for non-empty earlier. This is just in case. if length potential = 0 [ stop ] let focus-id one-of potential let num-worked 0 if table:has-key? worked-on-count focus-id [ set num-worked table:get worked-on-count focus-id ] work-on-feature focus-id usable-energy num-worked ;; update work id's set assigned remove focus-id join-lists newly-assigned assigned set worked-on lput focus-id worked-on set newly-assigned [] ] ;; continue most recent old work until you've been told stopped [ ifelse not empty? worked-on [ let focus-id last worked-on let num-worked 0 if table:has-key? worked-on-count focus-id [ set num-worked table:get worked-on-count focus-id ] work-on-feature focus-id usable-energy num-worked ][ recover-energy] ] ] [ set energy (energy + energy-recovery) ] end to recover-energy set energy (energy + energy-recovery) end ;; worker feature -> void ;; goals; choose from assigned, if feature doesn't exist, create it to work-on-feature [a-feature-id usable-energy previous-experience] let current-feature one-of (features-of current-product) with [fid = a-feature-id] ;; handle adding new feature ifelse current-feature = NOBODY [ hatch-features 1 [ set features-round (features-round + 1) if (any? (features-of ideal-product) with [fid = a-feature-id]) [ hide-turtle set xcor max-pxcor set ycor max-pycor ] set fid a-feature-id set product-id [id] of current-product set quality 0 ] ] ;; handle improving feature [ let quality-addon (previous-experience + 1) * (usable-energy / energy-per-quality) set quality-round (quality-round + quality-addon) ask current-feature [ set quality (quality + quality-addon)] ] set energy (energy - usable-energy) set energy-round (energy-round + usable-energy) end ;; manager -> void: ;; TODO: to publish-product if average-consumer-satisfaction < consumers-satisfaction-sensitivity [ ] end ;; turtle -> void to do-age set age (age + 1) end ;;;;;;;;;;;;;; END GO CODE ;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;; HELPERS CODE ;;;;;;;;;;;;;;;;;;;;;;; ;; used to update colors of turtles to indicate quality and energy to color-turtles ;; color products ask products [ set color orange ] ;; color special products ask no-product [ hide-turtle ] ask ideal-product [ set color green ] ask current-product [ set color yellow] ;; color features by quality let c-features features-of current-product ask implemented-ideal-features [ let c-quality [quality] of (one-of c-features with [fid = [fid] of myself]) set color palette:scale-gradient [[255 0 0] [0 255 0 ]] c-quality 0 100 ] ask not-implemented-ideal-features [ set color red ] ask c-features [ set color palette:scale-gradient [[255 0 0] [0 255 0 ]] quality 0 100 ] ask managers [ color-by-energy [[0 0 0] [0 0 240]]; [[255 25 0] [0 0 240]] ] ask workers [ color-by-energy [[0 0 0] [255 255 255]]; [[255 0 0] [255 255 255] ] ] ask consumers [ color-by-energy [[0 0 0] [127 0 255]]; [[255 0 0] [127 0 255]] ] end ;; used to update colors of turtles by energy to color-by-energy [colors] set color palette:scale-gradient colors energy 0 max-energy end ;; unimplemented any number number -> boolean: to-report nearish [v1 v2] report true end ;; helper to have consumer buy a new product to buy-market-product set owned-product market-product set bought-at-age [age] of market-product end ;; helper to get the features agentset that are related to a product to-report features-of [a-product] let a-product-id [id] of a-product report features with [product-id = a-product-id] end ;; helper to get satisfaction of consumers to-report average-consumer-satisfaction report total-consumers-satisfaction / (count consumers) end to-report total-consumers-satisfaction report sum [satisfaction] of consumers end ;; worker feature -> boolean: checks whether a worker has worker on ;; the feature before to-report worked-on-id? [a-feature-id] report member? a-feature-id worked-on end ;; worker feature -> boolean: checks whether a worker has worker on ;; the feature before to-report worked-on? [a-feature] report member? [fid] of a-feature worked-on end ;; any -> number: returns a sequence of natural numbers. to-report generate-product-id set product-id-sequence product-id-sequence + 1 report product-id-sequence end ;; void -> number: helper to generate a feature within the feature id space to-report generate-feature-id report random size-of-feature-space end ;; any (listof numbers) -> number: generates a feature id from the id space not in the list to-report generate-new-id [used-ids] let potential-feature-id generate-feature-id while [member? potential-feature-id used-ids] [ set potential-feature-id generate-feature-id ] report potential-feature-id end ;; any product -> number: analyzes features by comparing it to the ;; current ideal product to-report product-quality [a-product] let pid [id] of a-product report sum [quality] of features with [product-id = pid] end ;; any -> number : creates a productivity level to-report generate-productivity ifelse random-productivity? [report random-float max-productivity] [report max-productivity] end ;; wrapper to get the number of occurrences stored in hash table to-report occurrence [occurrences a-id] ifelse table:has-key? occurrences a-id [report table:get occurrences a-id] [report 0] end ;; helper to check whether something in a list is greater than corresponding value in other list to-report pair-greater [p1 p2 index] let p1-item item index p1 let p2-item item index p2 report p1-item > p2-item end ;; helper to get set of ideal features in current product to-report implemented-ideal-features let ideal-features features-of ideal-product let current-ids [fid] of features-of current-product report ideal-features with [member? fid current-ids] end ;; helper to get set of ideal features not in current product to-report not-implemented-ideal-features let ideal-features features-of ideal-product let current-ids [fid] of features-of current-product report ideal-features with [not member? fid current-ids] end ;; helper to get set of features in current product that are not ideal to-report market-extra-features let market-features features-of market-product let ideal-ids [fid] of features-of ideal-product report market-features with [not member? fid ideal-ids] end ;; calculates the benefit for the round to-report round-benefit let quality-benefit 10 let feature-benefit 15 report (quality-round * quality-benefit + (features-round * count implemented-ideal-features)) end to-report current-extra-features let current-features features-of current-product let ideal-ids [fid] of features-of ideal-product report current-features with [not member? fid ideal-ids] end ;; sets the shape of the feature depending whether it is implemented or superfluous. to set-feature-shapes ask implemented-ideal-features [set shape "circle"] ask not-implemented-ideal-features [set shape "circle 2"] ask current-extra-features [set shape "x"] end ;; helper to layout agentset in grid to grid-layout [agents min-x max-x min-y max-y max-row] if agents = NOBODY [stop] let cur-x min-x let cur-y max-y let num-rows (count agents / max-row) let x-offset (max-x - min-x) / max-row let y-offset (max-y - min-y) / num-rows ask agents [ set xcor cur-x set ycor cur-y let new-row? (floor ((cur-x + x-offset) / max-x)) > 0 ifelse new-row? [set cur-x min-x set cur-y (cur-y - y-offset)] [set cur-x (cur-x + x-offset)] ] end ;; helper to layout list in grid to grid-layout-list [agents min-x max-x min-y max-y max-row] if empty? agents [stop] let cur-x min-x let cur-y max-y let num-rows (length agents / max-row) let x-offset (max-x - min-x) / max-row let y-offset (max-y - min-y) / num-rows foreach agents [ ask ? [ set xcor cur-x set ycor cur-y let new-row? (floor ((cur-x + x-offset) / max-x)) > 0 ifelse new-row? [set cur-x min-x set cur-y (cur-y - y-offset)] [set cur-x (cur-x + x-offset)] ] ] end ;; resets measurements being measured per round to reset-round set total-benefit (round-benefit + total-benefit) set benefit-cost-round (round-benefit / (energy-round / energy-per-quality)) set features-round 0 set feedback-round 0 set quality-round 0 set energy-round 1 end
There is only one version of this model, created over 8 years ago by Adel Lahlou.
Attached files
File | Type | Description | Last updated | |
---|---|---|---|---|
AdelLahlou-FeedbackConstraintSatisfaction-EECS372.png | preview | Preview for 'AdelLahlou-FeedbackConstraintSatisfaction-EECS372' | over 8 years ago, by Adel Lahlou | Download |
This model does not have any ancestors.
This model does not have any descendants.