powered by NetLogo

view/download model file: EMS_ecology_model.nlogo

SUMMARY

This is a model of different ecoologies developing with evolution. This is an experimental model that combines elements of a meta-population model with a “McKane” style of simulated evolution (but with individuals rather than populations represented).

Each patch has a set of characteristics composed of a binary vector and a level of resources (energy) that is replenished each simulation tick.

Each individual of a species has the same gene composed of a vector of fixed length. It also has an energy level and an age. Each iteration a life-tax is subtracted from its energy. If its energy falls below 0 it dies. If its energy level exceeds a set level it reproduces into the same patch (with a possible mutation) - the energy of the offspring is subtracted from the parent. If its age exceeds the maximum age it also dies (unless maximum age is set to 0). There is a small probability of migrating to another patch (there are two settings for this - either to another random patch or only neighboring patches).

Energy is gained in one of two ways:

  1. by extraction from the environment by comparing its gene against the vector of characteristics for the patch it is on. In this case the scores of individuals that are achieve value > 0 determine the distribution of the fixed pot of energy for the patch.

  2. by eating other individuals. Each individual tries to eat a set number of random others on their patch. The success of this is determined by comparing its gene against the gene of the other. If the score is greater than a threshold (currently 0) then it eats the other, adsorbing a percentage of the other’s energy and the other dying.

Method of “comparison” in (1) and (2) above:

During initialisate a random square matrix with dimension of the same length as a gene is generated (this can be optionally forced to be anti-symmetric). This matrix determines the score of one gene against another gene or patch characteristic vextor. All the entries indicated by a “1” in both are summed, the first indicating the selected columns, the second the rows.

New species arise due to a mutation occuring during propagation or the introduction of a new random species from outside.

OUTPUTS

The world is divided into patches the background colouring indicates its characteristics.

Individuals are small stars (if never eaten another individual) or circles (getting bigger for each other they eat) if they have. Colouring indicates species. Position within patches is not significant and randomised.

Energy Distribnution is a histogram of the energy levels of individuals.

Tropic Level Distribution is a histogram of the trophic levels. This is of individuals not species, so if an individual has eaten another that has eaten a ‘herbivore’ then it has a trophic level of at least 2.

pi-t and pi-d is (an estimate of) the average hamming distance between pairs of indiviuduals in the whole simulation and within patches respectively.

F-st is (pi-t - pi-d) / pi-t and is a measure of the amount of variety between patches.

F-st, pi-t and pi-d are only calculated at the end of simulations or when the button is pressed since it takes a while to calculate them.

L0, L1, L2+ are the number of individuals at trophic levels 0, 1 and above 1.

INITIALISATION

Patches are initialised with a random set of characteristics depending on num-env-chars.

At the start a population of efficiency * food-rate / life-tax individuals is created with the an energy distibution of init-energy + random-normal 0 (init-energy / 4) and a genetic distribution depending on the initial-species-variety setting (see above).

There are two sensible sets of settings for this simulation:

  1. With initial-species-variety=1, new-species-prob=0 – so the initial variety ensures that some species are viable, resulting in a slow initial decline in number of species.

  2. With initial-species-variety=0, new-species-prob>0 – in this case species are introduced (McKane fashion) one by one until a viable one is discovered. In this case the stop-new-species-once-established? might be used to stop the introduction of random species after a viable population is established.

PARAMETERS AND SETTINGS

gene-size - the number of bits in an individual’s gene

num-env-chars - the number of (effective) bits in the characteristics of a patch (functions similar to an individual’s gene)

migration-prob - the probability that any individual will move to another patch each time click

mut-prob - the probability that a newly born individual will have its gene mutated

food-rate - how much energy is put into the patches each time click (evenly divided among patches)

life-tax - how much energy subtracted from each individual each time click (dies if energy is 0 or below)

init-energy - the energy of a new born (this is subtracted from the parent at birth)

efficiency - what proportion of energy of something eaten goes to predator (or to herbivore from patch)

reproduce-level - if an individual’s energy gets to this point it gives birth once (new born’s energy being then ssubtracted from it)

eating-tries - each tick each individual tries to eat this number of others on the same patch, but this only happens if they dominate them via the interaction matrix

max-age - if > 0 individuals die when they reach this age in simulation ticks (otherwise no age ceiling)

max-store - if > 0 this is the upper bound on what energy individuals can accumulate (rest is lost to system)

init-new-species-prob - probability of a new individual with a random geneome being introduced each time click

stop-new-species-once-established? - if set stops new individuals with new genomes being introduced into the simulation once a viable population is established

initial-species-variety - 0/1 - if 0 simulation starts with a single individual (if this is not successful relies on a new individual being intyroduced via init-new-species-prob), if 1 starts with a full population with random genes

rand-death-prob - the probability an individual dies each time click (apart from other reasons)

anti-sym-mat? - forces the interaction matrix generated at start to be anti-symmetric

migrate-near? - if true then individuals migrate (if they do) to a neighbouring patch if false to a random other patch

allow-cannibals? - if true individuals of the same species can eat each other, if not can only eat those of another species

neutral? - if true then all individuals on a patch get the same amount of energy from the patch regardless of their geneome (otherwise they have to dominate the patch via the interaction matrix)

max-time - if > 0 the time at which the simulation is halted

SECOND STAGE ANALYSIS

At any point the state of the world can be saved to disk or retrieved (using the Save and Load buttons). When this happens the filename uses that in the “title” input box.

affected-char - if > 0 this prevents the numbered characteristic being taken into acount during dominance calculations using the interaction matrix. In other words this characteristic is supressed in terms of its efficacy.

The the Start-A, Do-A and End-A buttons initialise, do and calculate final stats from this point (up to max-time) with the affected-char intervention in place

OUTPUTS AND MONITORS

In current tick:

Eats - how many are eaten
Deaths - total systematic deaths (eaten, starve, got too old)
Births - number of new individuals born due to parent reaching required energy
Pop - number of live individuals
Species - how many distinct genomes there are in living individuals
Starve - how many died of lack of energy
Old - how many died due to reaching max-age
Migr - how many migrated to another patch
Rand Die - how many died randomly (due to rand-death-prob)
secs/tick - how long current simulation tick took to compute (in seconds)
L0 - proportion of individuals that have not eated anyone ever (herbivores)
L1 - proportion of individuals that have ever eaten a herbivore
L2 - proportion of individuals that have ever eaten a carnivore

CummS - how many distinct geneomes have been created in current simulation

Only calculated when press Calc button or at end of simulation. All are about diversity measured as the average hamming distance between pairs of distinct individuals (estimated using random sample of 10000)

pi-t - the overall diversity
pi-d - diversity within patches
F-st - (pi-t - pi-d) / pi-t i.e. how much diversity is inter-patch
pi-env - diversity within all patches with same characteristics
F-env - (pi-t - pi-env) / pi-t how much diversity is inter-ptach-type
F-denv (pi-env - pi-d) / pi-env how much within patch diversity is due to variation between patches with same characteristics

GRAPHS

Energy Distribution - histogram of the energy levels of individuals
Tropic Level Distribution - a histogram of number of individuals at each tropic level
Population - graph of number of living individuals
Number of Species - graph of number of distinct geneomes in current population
Log Population Types - graph of the number of individuals at different tropic levels (on a logarithmic scale)

RELATED MODELS

This model relates to the McKane series of models to simulation the evolution of food webs, to meta-population models and to the “Patterns of genetic variation in populations of infectious agents” paper by Isabel Gordo and Paulo RA Campos in BMC Evoilutionary Biology.

CREDITS AND REFERENCES

Bruce Edmonds
7/11/12

CODE

extensions [table matrix]

breed [entities entity]
breed [people person]

globals [any-change? no-change-for end-tick dom-matrix init-pop-size num-patches num-empty-env
         col-thresh trace? num-death-entitys num-starve num-eat num-born cumm-num-species new-species-prob
         num-death-entitys-disp num-starve-disp num-eat-disp num-born-disp num-migrate num-migrate-disp
         max-size dom-floor num-extinctions time-per-tick num-die-old num-die-old-disp bit-mutate-prob
         num-ticks-with-non-zero-pop survival-threshold col-incr dom-matrix-list species-col-entity-list species-num-entity-list dv-vals-list
         filename species-col-entity species-num-entity species-col-people species-num-people dv-vals 
         pi-t pi-d F-st pi-env F-env F-denv num-species l0 l1 l2+ patch-set-list list-patch-chars
         analysis-phase? sample-size death-entity-threshold num-die-rand
         s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 pi1 pi2 pi3 pi4 pi5 pi6 pi7 pi8 pi9 pi10 pi11 pi12 pi13 pi14 pi15 pi16
         num-born-people num-starve-people num-die-old-people num-die-rand-people num-die-old-people-disp num-starve-people-disp
         num-species-people num-species-people-cumm between-people-count num-variants species-col-people-list species-num-people-list
         life-tax init-energy num-entities num-people av-tolerance sd-tolerance av-sharing sd-sharing av-learning sd-learning
         pi-t-people pi-d-people F-st-people pi-env-people F-env-people F-denv-people 
         ]

entities-own [gene energy level age]
people-own [gene tag tolerance energy level age num-sharing num-learning generation] 
patches-own [chars resource]

to setup
  clear-all
  resize-world 0 (world-size - 1) 0 (world-size - 1)
  set life-tax 0.05
  set init-energy 1.0
  ifelse (strip-spaces title) = "" [set filename "iEMS Model + social"] [set filename strip-spaces title]
  ;;  set filename (word filename "-" (substring date-and-time 16 length date-and-time) "-" behaviorspace-run-number)
  ifelse initial-species-variety = 0
    [set init-pop-size 1]
    [set init-pop-size (2 / 3) * efficiency * food-rate / life-tax]
  set num-patches (max-pxcor + 1) * (max-pycor + 1)
  set survival-threshold 2 * food-rate / (life-tax * num-patches)
  set death-entity-threshold 0
  set col-incr 30
  set num-empty-env gene-size - num-env-chars
  set col-thresh 20
  set max-size 0.25
  set sample-size 10000
  set new-species-prob init-new-species-prob
  set trace? false
  set analysis-phase? false
  set dom-floor 0
  set num-ticks-with-non-zero-pop max (list 200 max-age (2 * init-energy / life-tax))
  set cumm-num-species 0
  set num-species-people-cumm 0
  set num-variants 0
  set species-col-entity table:make
  set species-num-entity table:make
  set species-col-people table:make
  set species-num-people table:make
  set dv-vals table:make
  clear-save-lists

  set dom-matrix matrix:from-row-list n-values gene-size [n-values gene-size [rand-val]]
  if anti-sym-mat? [set dom-matrix a-sym dom-matrix]
  
  set list-patch-chars []
  let n 0
  ask patches [
    set resource 0
    set chars sentence n-values num-env-chars [rand-bin] n-values num-empty-env [0]
    if not member? chars list-patch-chars [set list-patch-chars fput chars list-patch-chars]
    set pcolor (list (col-thresh * (1 + first chars)) (col-thresh * (1 + second chars)) (col-thresh * (1 + third chars)))
  ]
  set patch-set-list map [patches with [chars = ?]] list-patch-chars
  
  let temp-gene n-values gene-size [rand-bin]
  create-entities init-pop-size [
    set age 0 + random (max-age / 3)
    set energy init-energy + random-normal 0 (init-energy / 3)
    ifelse initial-species-variety = 1
      [set gene n-values gene-size [rand-bin]]
      [set gene temp-gene]
    set color new-gene-entity gene
    setxy random (max-pxcor + 1) random (max-pycor + 1)
    set shape "star"
    set size 0.1
    set level 0
    show-turtle
    place
  ]
  
  reset-ticks
end

to place
  set xcor [pxcor] of patch-here + random-float 0.9 - 0.45
  set ycor [pycor] of patch-here + random-float 0.9 - 0.45
end

to-report a-sym [mat]
  let m2 matrix:plus mat matrix:transpose mat
  report m2
end

to-report rand-val
;;  report (random-float 2) - 1
  report random-normal 0 0.3333
end

to-report rand-bin
  report random 2
end

to-report hamming-dist [vec1 vec2]
  report sum (map [ifelse-value (?1 = ?2) [0] [1]] vec1 vec2)
end

to-report name
  report (word self)
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to go
  reset-timer
  ;; if time is done stop simulation
;;  if max-time > 0 and ticks  > max-time [
;;      stop
;;    ]

  set end-tick ticks
  set any-change? false
  if new-species-prob > 0 [
    if count entities > 0 
      [set num-ticks-with-non-zero-pop num-ticks-with-non-zero-pop + 1]
    if num-ticks-with-non-zero-pop > survival-threshold [set new-species-prob 0]
  ]
  
  ;; distribute resources to patches
  ask patches [set resource resource + food-rate / num-patches]
  
  ;; entities
  set num-starve 0
  set num-die-old 0
  set num-die-rand 0
  ;; life tax, aging and death-entity
  ask entities [
    set energy energy - life-tax
    set age age + 1
    if energy < death-entity-threshold [set num-starve num-starve + 1 death-entity]
    if max-age > 0 and age > max-age [set num-die-old num-die-old + 1 death-entity]
    if prob rand-death-entity-prob [set num-die-rand num-die-rand + 1 death-entity]
  ]
  set num-die-old-disp num-die-old
  set num-starve-disp num-starve
  
  ;; people dying
  
  ;; people
  set num-starve-people 0
  set num-die-old-people 0
  set num-die-rand-people 0
  ask people [
    set num-learning 0
    set num-sharing 0
  ]
  ;; life tax, aging and death-entity
  ask people [
    set energy energy - life-tax
    set age age + 1
    if energy < death-entity-threshold [set num-starve-people num-starve-people + 1 death-people]
    if max-age-people > 0 and age > max-age-people [set num-die-old-people num-die-old-people + 1 death-people]
    if prob rand-death-entity-prob [set num-die-rand-people num-die-rand-people + 1 death-people]
  ]
  set num-die-old-people-disp num-die-old-people
  set num-starve-people-disp num-starve-people
  
  ;; new entrants from outside
  if prob new-species-prob or (initial-species-variety = 0 and count entities = 0) [
    create-entities 1 [
      set age 0
      set energy init-energy + random-normal 0 (init-energy / 4)
      set gene n-values gene-size [rand-bin]
      set color new-gene-entity gene
      setxy random (max-pxcor + 1) random (max-pycor + 1)
      set shape "star"
      set size 0.1
      set level 0
      show-turtle
      place
    ]
  ]
  
  ;; extracting energy from the patch
  ;; at the moment the energy is shared by any > dom-floor proportionately
  ;; entities only unless people-f-env? is on
  ask patches [
    let distributees no-turtles
    ifelse people-f-env?
      [set distributees (turtle-set entities-here people-here)]
      [set distributees entities-here]
    if not any? distributees [stop]
    let tl sort distributees
    let nt (length tl) - 1
    let rl []
    ifelse neutral? 
      [set rl map [0.01] tl]
      [set rl map [? - dom-floor] map [max list dom-floor dv ([gene] of ?) chars] tl]
    let sumrl sum rl
    if sumrl = 0 [stop]
    let lf resource / sumrl
    let i 0
    foreach seq 0 nt 1 [
      set i item ? rl
      if i > 0 [
        ask item ? tl [set energy energy + efficiency * lf * i]
        set resource resource - lf * i
      ]
    ]
  ]
  
  ;; predation
  ;; both entities and people
  set num-eat 0
  ask turtles [
    foreach safeSubList (shuffle sort other entities-here) 0 eating-tries [
      if dom? gene [gene] of ? [
        set level 1 + [level] of ?
        set energy energy + efficiency * [energy] of ?
        ask ? [ifelse breed = entities [death-entity] [death-people]]
        set num-eat num-eat + 1
        ifelse breed = entities 
          [set shape "circle"]
          [set shape "face happy"]
        set size min list max-size size + 0.05
      ]
    ]
  ]
  set num-eat-disp num-eat
  
  ;; reduce all stores to max-store if this is > 0
  if max-store > 0 [
    ask entities [
      set energy min list energy max-store
    ]
  ]
  if max-people-store > 0 [
    ask people [
      set energy min list energy max-people-store
    ]
  ]
  
  ;; people bits here
  ;; initial people
  if ticks = people-enter [init-people]
  ifelse not any? people 
    [set between-people-count between-people-count + 1]
    [set between-people-count 0]
  if ticks > people-enter and between-people-count >= time-between-invasions and not any? people [init-people]
  
  ;; people births
  set num-born-people 0
  let old-gen 0
  ask people [
    if energy >= reproduce-level-people [
      set old-gen generation
      hatch 1 [
        let col [0 0 0]
        set age 0
        set generation old-gen + 1
        set energy init-energy
        set size 0.2
        set shape "face neutral"
        set level 0
        set color mutated-gene-people gene
        set tag (mutate-sd tag tag-mut-sd) mod 1
        ifelse tol-on? 
          [set tolerance min list max-tolerance max list 0 (mutate-sd tolerance tol-mut-sd)]
          [set tolerance 2]
        place
      ]
      set energy energy - 2 * init-energy
    ]
  ]
  ;; people learning, innovating, sharing
  let poss-people no-turtles
  let poss-people-better no-turtles
  let my-tag 0
  let my-tol 0
  let my-energy 0
  let oth nobody
  let old-gene []
  ask people [
    if prob innovation-prob [
      set gene mutate gene (1 / gene-size)
      set color mutated-gene-people gene
    ]
    set my-tag tag
    set my-tol tolerance
    set my-energy energy
    set old-gene gene
    
    if coop-radius = 1 [set poss-people other people-here with [(tag-dist tag my-tag) < my-tol]]
    if coop-radius = 5 [set poss-people other people-here5 with [(tag-dist tag my-tag) < my-tol]]
    if coop-radius = 9 [set poss-people other people-here9 with [(tag-dist tag my-tag) < my-tol]]
    
    if any? poss-people [
      if prob learn-prob [
        set poss-people-better (poss-people with [energy > my-energy])
        if any? poss-people-better [
          set gene learn-from gene ([gene] of one-of poss-people-better)
          if gene != old-gene [
            set color mutated-gene-people gene
            remove-one old-gene
            set num-learning num-learning + 1
          ]
        ]
      ]
      ;; people sharing
      repeat share-tries [
        if energy > min-share-level [
          set num-sharing num-sharing + 1
          set oth one-of poss-people
          set energy energy - 1
          ask oth [set energy energy + share-efficiency]
        ]
      ]
    ]
  ]
 
  ;; entity births
  set num-born 0
  ask entities [
    if energy >= reproduce-level [
      hatch 1 [
        let col [0 0 0]
        set age 0
        set energy init-energy
        set size 0.1
        set shape "star"
        set level 0
        if prob mut-prob [
          ;; Note!! a prob of each bit being flipped of mut-prob as well as chance for this to happen
          set gene mutate gene (1 / gene-size)
        ]
        set color mutated-gene-entity gene
        place
      ]
      set num-born num-born + 1
      set energy energy - init-energy
    ]
  ]
  set num-born-disp num-born
  
  ;; migrations
  ;; all 
  set num-migrate 0
  ifelse migrate-near? [
    ask entities [if prob migration-prob [move-near]]
  ] [
    ask entities [
      if prob migration-prob [
        setxy random (max-pxcor + 1) random (max-pycor + 1)
        place
        set num-migrate num-migrate + 1
      ]
    ]
  ]
  
  ;; people
  ifelse migrate-near? [
    ask people [if prob migration-prob-people [move-near]]
  ] [
    ask people [
      if prob migration-prob-people [
        setxy random (max-pxcor + 1) random (max-pycor + 1)
        place
        set num-migrate num-migrate + 1
      ]
    ]
  ]
  set num-migrate-disp num-migrate
  
  set num-variants 
    ifelse-value any? people 
    [length remove-duplicates [gene] of people]
    [0]
  set num-species table:length species-num-entity
  if any? people [set num-species-people table:length species-num-people]
  set l0 safeDiv count entities with [level = 0] count entities
  set l1 safeDiv count entities with [level = 1] count entities
  set l2+ safeDiv count entities with [level > 1] count entities
  set num-people count people
  set num-entities count entities
  set av-tolerance ifelse-value any? people [mean [tolerance] of people] [0]
  set sd-tolerance ifelse-value (count people > 1) [standard-deviation [tolerance] of people] [0]
  set av-sharing ifelse-value any? people [mean [num-sharing] of people] [0]
  set sd-sharing ifelse-value (count people > 1) [standard-deviation [num-sharing] of people] [0]
  set av-learning ifelse-value any? people [mean [num-learning] of people] [0]
  set sd-learning ifelse-value (count people > 1) [standard-deviation [num-learning] of people] [0]
  
  set time-per-tick timer
  
  if max-time > 0 and ticks  >= max-time [
    show "finished"
    calc-stats 
    calc-stats-people
    end-analysis
    stop
  ]
  tick
end

to-report dv [g1 g2]
  let op 0
    ifelse table:has-key? dv-vals list g1 g2
      [set op table:get dv-vals list g1 g2]
      [set op calc-dv g1 g2
       table:put dv-vals list g1 g2 op]
  report op 
end

to clear-dv-cache
  table:clear dv-vals
end

to-report calc-dv [g1 g2]
;;  if affected-char > 0 [
  if affected-char > 0 [
    set g1 replace-item (affected-char - 1) g1 0
    set g2 replace-item (affected-char - 1) g2 0
  ]
  let op 0
  let i 0
  foreach (seq 0 (gene-size - 1) 1) [
    set i ?
    if (item i g1) != 0 [
      foreach seq 0 (gene-size - 1) 1 [
        set op op + (item ? g2) * (matrix:get dom-matrix i ?)
      ]
    ]
  ]
  report op
end

to move-near
  let ns neighbors
  if not any? ns [stop]
  let next-patch one-of ns
  setxy [pxcor] of next-patch [pycor] of next-patch
  place
  set num-migrate num-migrate + 1
end

to-report rand-plus-minus
  report (2 * random 2) - 1
end

to-report dom? [g1 g2]
  if not allow-cannibals? and g1 = g2 [report false]
  report dv g1 g2 > dom-floor
end

to-report sel-pos [pl vl]
  if empty? pl [report []]
  ifelse first pl > 0 
    [report fput first vl (sel-pos but-first pl but-first vl)]
    [report sel-pos but-first pl but-first vl]
end

to-report shade [cl]
  report (list chc first cl chc second cl chc last cl)
end

to-report rand-col
  report (list rand-rbg-val rand-rbg-val rand-rbg-val)
end

to-report rand-rbg-val
  report col-thresh + random-float (255 - col-thresh)
end
  
to-report chc [v]
  report min list 255 max list col-thresh ch-val v
end

to-report ch-val [v]
  if v >= 255 [report v - col-incr - random col-incr]
  if v <= col-thresh [report v + col-incr + random col-incr]
  ifelse 0 = random 2
    [report v + col-incr + random col-incr]
    [report v - col-incr - random col-incr]
end

to-report mutate [g p]
;;  report flip-bit random gene-size g
  let op []
  repeat length g [
    ifelse prob p  
      [set op fput (1 - first g) op]
      [set op fput first g op]
    set g but-first g
  ]
  report reverse op
end

to-report flip-bit [p g]
  report replace-item p g (1 - item p g)
end

to calc-stats
  set pi-t 0
  set pi-t 0
  set pi-d 0
  set F-st 0
  set pi-env 0
  set F-env 0
  let ot nobody
  let my-gene []
  let ps nobody
  let p nobody
  let p1 nobody
  let p2 nobody
  if any? entities [
    repeat sample-size [
      ask one-of entities [
        set my-gene gene
        if any? other entities
          [ask one-of other entities  [set pi-t pi-t + hamming-dist my-gene gene]]
      ]
    ]
    repeat sample-size [
      ask one-of entities [
        set my-gene gene
        if any? other entities-here 
           [ask one-of other entities-here [set pi-d pi-d + hamming-dist my-gene gene]]
      ]
    ]
    set ps map [entities-from ?] patch-set-list
    repeat sample-size [
       set p random-member ps
       if any? p [
         set p1 one-of p
         ask p1 [set p2 one-of other (turtle-set ps)]
         if p2 != nobody [
           set pi-env pi-env + hamming-dist [gene] of p1 [gene] of p2
         ]
       ]
    ]
    set pi-d safeDiv pi-d sample-size  
    set pi-t safeDiv pi-t sample-size
    set pi-env safeDiv pi-env sample-size
    set F-st safeDiv (pi-t - pi-d) pi-t
    set F-env safeDiv (pi-t - pi-env) pi-t
    set F-denv safeDiv (pi-env - pi-d) pi-env
  ]
end

to calc-stats-people
  set pi-t-people 0
  set pi-t-people safeDiv pi-t-people sample-size
  set pi-d-people 0
  set F-st-people 0
  set pi-env-people 0
  set F-env-people 0
  let ot nobody
  let my-gene []
  let ps nobody
  let p nobody
  let p1 nobody
  let p2 nobody
  if any? people [
    repeat sample-size [
      ask one-of people [
        set my-gene gene
        if any? other people
          [ask one-of other people  [set pi-t-people pi-t-people + hamming-dist my-gene gene]]
      ]
    ]
    repeat sample-size [
      ask one-of people [
        set my-gene gene
        if any? other people-here 
           [ask one-of other people-here [set pi-d-people pi-d-people + hamming-dist my-gene gene]]
      ]
    ]
    set ps map [people-from ?] patch-set-list
    repeat sample-size [
       set p random-member ps
       if any? p [
         set p1 one-of p
         ask p1 [set p2 one-of other (turtle-set ps)]
         if p2 != nobody [
           set pi-env-people pi-env-people + hamming-dist [gene] of p1 [gene] of p2
         ]
       ]
    ]
    set pi-d-people safeDiv pi-d-people sample-size  
    set pi-t-people safeDiv pi-t-people sample-size
    set pi-env-people safeDiv pi-env-people sample-size
    set F-st-people safeDiv (pi-t-people - pi-d-people) pi-t-people
    set F-env-people safeDiv (pi-t-people - pi-env-people) pi-t-people
    set F-denv-people safeDiv (pi-env-people - pi-d-people) pi-env-people
  ]
end

to-report ecology-state
  if count entities < 10 [report "non-viable"]
  if num-species < 2 [report "one-species"]
  if l1 = 0 [report "hebivore"]
  report "mixed"
end

to-report people-state
  if not any? people [report "none"]
  if not any? people with [level > 0] [report "starving"]
  if not any? people with [generation > 0] [report "barren"]
  report "viable"
end

to-report entities-from [ps]
  report entities with [member? patch-here ps]
end

to-report people-from [ps]
  report people with [member? patch-here ps]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to a-a-PEOPLE-STUFF end

to init-people
  let a-random-gene n-values gene-size [rand-bin]
  let a-rand-x random (max-pxcor + 1) 
  let a-rand-y random (max-pycor + 1)
  create-people num-people-enter [
    set age 0
    set generation 0
    set energy init-energy + random-normal 0 (init-energy / 4)
    ifelse (init-variety = 0)
        [set gene a-random-gene]
        [set gene n-values gene-size [rand-bin]]
    set color new-gene-people gene
    setxy random (max-pxcor + 1) random (max-pycor + 1)
    set shape "face neutral"
    set size 0.2
    set level 0
    set tag random-float 1
    ifelse tol-on?
      [set tolerance random-float max-tolerance]
      [set tolerance 2]
    setxy a-rand-x a-rand-y
    show-turtle
    place
  ]
end

to-report learn-from [mg og]
  let ps random gene-size
  report replace-item ps mg (item ps og)
end

to-report mutate-sd [vl sd]
  report (vl + random-normal 0 sd) mod 1
end

to-report tag-dist [t1 t2]
  let mn min list t1 t2
  let mx max list t1 t2
  report min list (mx - mn) (1 + mn - mx)
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to a-a-GENE-STUFF end

to-report new-gene-entity [g]
  ifelse table:has-key? species-num-entity g [
    table:put species-num-entity g 1 + table:get species-num-entity g
    set color table:get species-col-entity g
  ] [
    set color rand-col
    table:put species-col-entity g color
    table:put species-num-entity g 1
    set cumm-num-species cumm-num-species + 1
  ]
  report color
end

to-report mutated-gene-entity [g]
  ifelse table:has-key? species-num-entity g [
    table:put species-num-entity g 1 + table:get species-num-entity g
    set color table:get species-col-entity g
  ] [
    set color shade color
    table:put species-col-entity g color
    table:put species-num-entity g 1
    set cumm-num-species cumm-num-species + 1
  ]
  report color
end

to-report new-gene-people [g]
  ifelse table:has-key? species-num-people g [
    table:put species-num-people g 1 + table:get species-num-people g
    set color table:get species-col-people g
  ] [
    set color rand-col
    table:put species-col-people g color
    table:put species-num-people g 1
  ]
  report color
end

to-report mutated-gene-people [g]
  ifelse table:has-key? species-num-people g [
    table:put species-num-people g 1 + table:get species-num-people g
    set color table:get species-col-people g
  ] [
    set color shade color
    table:put species-col-people g color
    table:put species-num-people g 1
  ]
  report color
end


to death-entity
  let num-of-this (table:get species-num-entity gene) - 1
  table:put species-num-entity gene num-of-this
  if num-of-this < 1 [
    table:remove species-col-entity gene
    table:remove species-num-entity gene
  ]
  die
end


to death-people
  remove-one gene
  die
end

to remove-one [g]
  let num-of-this (table:get species-num-people g) - 1
  table:put species-num-people g num-of-this
  if num-of-this < 1 [
    table:remove species-col-people g
    table:remove species-num-people g
  ]
end
        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to a-a-SAVE-LOAD end

to save-world
  set dom-matrix-list matrix:to-row-list dom-matrix
  set species-col-entity-list table:to-list species-col-entity
  set species-num-entity-list table:to-list species-num-entity
  set species-col-people-list table:to-list species-col-people
  set species-num-people-list table:to-list species-num-people  
  export-world (word title "-state.csv")
end

to load-world
  let fn (word title "-state.csv")
  if not file-exists? fn
    [set fn user-file]
  import-world fn
  set dom-matrix matrix:from-row-list dom-matrix-list
  set species-col-entity table:from-list species-col-entity-list
  set species-num-entity table:from-list species-num-entity-list
  set species-col-people table:from-list species-col-people-list
  set species-num-people table:from-list species-num-entity-list  
  set dv-vals-list []
  table:clear dv-vals
  set analysis-phase? true
end

to clear-save-lists
  set dom-matrix-list []
  set species-col-entity-list [] 
  set species-num-entity-list []
  set species-col-people-list []
  set species-num-people-list []
  set dv-vals-list []
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to a-a-ANALYSIS end

to start-analysis
  set analysis-phase? true
  clear-dv-cache
  random-seed new-seed
  ;; stuff for running sim with params
;;  set learn-prob learn-prob-p
;;  set init-variety init-variety-p
;;  set num-people-enter num-people-enter-p
;;  set num-env-chars num-env-chars-p
;;  set init-variety init-variety-p
;;  set tag-mut-sd tag-mut-sd-p
;;  set max-age-people max-age-people-p
;;  set migrate-near? migrate-near?-p
;;  set reproduce-level reproduce-level-p
;;  set innovation-prob innovation-prob-p
;;  set rand-death-entity-prob rand-death-entity-prob-p
;;  set title title-p
;;  set max-people-store max-people-store-p
;;  set migration-prob migration-prob-p
;;  set eating-tries eating-tries-p
;;  set share-tries share-tries-p
;;  set max-store max-store-p
;;  set time-between-invasions time-between-invasions-p
;;  set mut-prob mut-prob-p
;;  set max-tolerance max-tolerance-p
;;  set reproduce-level-people reproduce-level-people-p
;;  set max-time max-time-p
;;  set min-share-level min-share-level-p
;;  set max-age max-age-p
;;  set people-enter people-enter-p
;;  set efficiency efficiency-p
;;  set neutral? neutral?-p
;;  set share-efficiency share-efficiency-p
;;  set tol-mut-sd tol-mut-sd-p
;;  set food-rate food-rate-p
;;  set tol-on? tol-on-p?
;;  set coop-radius coop-radius-p
;;  set people-f-env? people-f-env-p?
end

to end-analysis
  calc-niche-stats
end

to calc-niche-stats
  let p 0 let ps nobody let as nobody let char-num 0
  let list-patch-nums map [num-from-binvec ? num-env-chars] list-patch-chars

  if num-env-chars < 1 [stop]
    set char-num 1
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s1 calc-ns as
  set pi1 calc-pi as
  ]
    set char-num 2
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s2 calc-ns as
  set pi2 calc-pi as
  ]
  if num-env-chars < 2 [stop]
    set char-num 3
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s3 calc-ns as
  set pi3 calc-pi as
  ]
    set char-num 4
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s4 calc-ns as
  set pi4 calc-pi as
  ]
    if num-env-chars < 3 [stop]
    set char-num 5
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s5 calc-ns as
  set pi5 calc-pi as
  ]
    set char-num 6
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s6 calc-ns as
  set pi6 calc-pi as
  ]
    set char-num 7
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s7 calc-ns as
  set pi7 calc-pi as
  ]
    set char-num 8
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s8 calc-ns as
  set pi8 calc-pi as
  ]
  if num-env-chars < 4 [stop]
    set char-num 9
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s9 calc-ns as
  set pi9 calc-pi as
  ]
    set char-num 10
  set p position (char-num - 1) list-patch-nums 
  if p != false [
    set ps item p patch-set-list
    set as entities-from ps
    set s10 calc-ns as
    set pi10 calc-pi as
  ]
    set char-num 11
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s11 calc-ns as
  set pi11 calc-pi as
  ]
    set char-num 12
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s12 calc-ns as
  set pi12 calc-pi as
  ]
    set char-num 13
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s13 calc-ns as
  set pi13 calc-pi as
  ]
    set char-num 14
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s14 calc-ns as
  set pi14 calc-pi as
  ]
      set char-num 15
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s15 calc-ns as
  set pi15 calc-pi as
  ]
    set char-num 16
  set p position (char-num - 1) list-patch-nums 
  if p != false [
  set ps item p patch-set-list
  set as entities-from ps
  set s16 calc-ns as
  set pi16 calc-pi as
  ]
end

to-report calc-pi [ts]
  if count ts <= 1 [report 0]
  let op 0 let t1 nobody let t2 nobody
  repeat sample-size [
    set t1 one-of ts
    ask t1 [set t2 one-of other ts]
    set op op + hamming-dist [gene] of t1 [gene] of t2
  ]
  report op / sample-size
end

to-report calc-ns [ts]
  report length remove-duplicates [gene] of ts
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
to a-a-GEN-UTILS end

to-report people-here5
  report (turtle-set people-here people-on neighbors4)
end

to-report people-here9
  report (turtle-set people-here people-on neighbors)
end

to-report sign [num]
  if num = 0 [report 0]
  ifelse num > 0
    [report 1]
    [report -1]
end

to-report num-from-binvec [binvec numplaces]
  let op 0
  foreach seq 0 (numplaces - 1) 1 [
    set op op + (2 ^ ?) * item ? binvec
  ]
  report op
end

to-report second [l]
  report first but-first l
end

to-report num-links
  report count my-links
end

to-report set-pos [pos lis]
  report replace-item pos lis 1
end

to-report clear-pos [pos lis]
  report replace-item pos lis 0
end

to-report safe-item [pos lis]
  if pos > (length lis - 1) [report 0]
  report item pos lis
end

to-report remove-list [remlis lis]
  let opl lis
  foreach remlis [
    set opl remove ? lis
  ]
  report opl
end

to-report n-colours [n]
  ;; produces a list of n random visible colurs (not too near black)
  report n-values n [(list (10 + random 245) (10 + random 245) (10 + random 245))]
end

to-report poss-of-len [dim]
  if dim <= 0 [report [[]]]
  let poss-minus1 poss-of-len (dim - 1)
  report sentence (map [fput 0 ?] poss-minus1) (map [fput 1 ?] poss-minus1)
end

to pause
  if not user-yes-or-no? (word "Continue?") [error "User halted simulation!!"]
end

to-report showpause [inp]
  if not user-yes-or-no? (word "Value is: " inp " -- Continue?") [error "User halted simulation!!"]
  report inp
end

to ipat [p1 p2]
  inspect patch p1 p2
end

to ith
  ask entities-here [inspect self]
end

to-report link-breed [p1 p2]
  let pl []
  ask p1 [set pl sort my-links]
  ask p2 [
    let p2l sort my-links
    set pl filter [member? ? p2l] pl
  ]
  if empty? pl [report "none"]
  report [breed] of (random-member pl)
end
  
to-report random-member [ls]
  report item (random length ls) ls
end

to-report prob [p]
  report random-float 1 < p
end

to-report subtract-list [lis1 lis2]
  report filter [not member? ? lis2] lis1
end

to-report safeSubList [lis srt en]
  let len length lis
  if en < 1 or srt > len [report []]
  report subList lis max list 0 srt min list en len
end

to-report safe-n-of [nm lis]
  if is-list? lis [if length lis >= nm [report n-of nm lis]]
  if is-agentset? lis [if count lis >= nm [report n-of nm lis]]
  report lis
end

to-report safe-one-of [lis]
  report safe-n-of 1 lis
end

to-report flatten-once [lis]
  let op-list []
  foreach lis [
    foreach ? [set op-list fput ? op-list]
  ]
  report op-list
end

to-report minList [lis1 lis2]
  report (map [min list ?1 ?2] lis1 lis2)
end

to-report maxList [lis1 lis2]
  report (map [max list ?1 ?2] lis1 lis2)
end

to-report sumList [lis1 lis2]
  report (map [?1 + ?2] lis1 lis2)
end

to-report sdList [sqLis sumLis numLis] 
  report (map [sqrt max (list 0 ((?1 / numLis) - ((?2 / numLis) ^ 2)))] sqLis sumLis)
end

to-report fputIfNew [exLisLis newLis]
  report (map [ifelse-value (member? ?2 ?1) [?1] [fput ?2 ?1]] exLisLis newLis)
end

to-report csv-string-to-list [str]
  let lis []
  while [not empty? str] [
    set lis fput next-value str lis
    set str after-next str
  ]  
  report reverse lis
end  

to-report after-next [str]
  let pos-comma position "," str
  if pos-comma != false [report subString str (pos-comma + 1) length str]
  report ""
end  

to-report next-value [str]
  let pos-comma position "," str
  if pos-comma != false [
    report read subString str 0 pos-comma
    ]
  report read str
end

to-report read [str]
  set str strip-spaces str
  if empty? str [report nobody]
    ifelse is-string-a-number? str
      [report read-from-string str]
      [report str]
end  

to-report strip-spaces [str]
  report strip-leading-spaces strip-trailing-spaces str
end  

to-report strip-leading-spaces [str]
  if empty? str [report str]
  if first str != " " [report str]
  report strip-leading-spaces but-first str
end

to-report is-string-a-number? [str]
  if empty? str 
    [report false]
  report is-nonempty-string-a-number? str
end

to-report is-nonempty-string-a-number? [str]
  if empty? str [report true]
  let ch first str
  if ch = "." [report is-string-digits? but-first str]
  if not is-str-digit? ch [report false]
  report is-nonempty-string-a-number? but-first str
end

to-report is-string-digits? [str]
  if empty? str [report true]
  let ch first str
  if not is-str-digit? ch [report false]
  report is-string-digits? but-first str
end  
  
to-report is-str-digit? [ch]
  ifelse ch >= "0" and ch <= "9"
    [report true]
    [report false]
end

to-report strip-trailing-spaces [str]
  if empty? str [report str]
  if last str != " " [report str]
  report strip-trailing-spaces but-last str
end  

to-report insert [itm ps lis]
  report (sentence sublist lis 0 ps (list itm) sublist lis ps (length lis))
end

to-report insertAfter [itm ps lis]
  report insert itm (ps + 1) lis
end

to-report num-nodes [lis]
  report length nodes-in lis
end

to-report nodes-in [lis]
  if not is-list? lis [report (list lis)]
  let op-list []
  foreach lis [set op-list append op-list nodes-in ?]
  report op-list
end

to-report third [lis]
  report item 2 lis
end

to XXX
  let tt 1 
  set tt tt - 1
  set tt 1 / tt
end

to-report showPass [arg]
  show arg
  report arg
end

to-report posBiggest [lis]
  report position (reduce [ifelse-value (?1 >= ?2) [?1] [?2]] lis) lis 
end

to-report allPos [expr]
  let oplis [[]]
  foreach but-first (n-values (length expr) [?]) [
    let ps ?
    let posLis allPos (item ps expr)
    set opLis append (map [fput ps ?1] posLis) opLis
  ]
  report opLis
end

to-report replaceAtPos [posList baseExpr insExpr]
  if posList = [] [report insExpr]
  report replace-item (first posList) baseExpr (replaceAtPos (but-first posList) (item first posList baseExpr) insExpr)
end

to-report atPos [posList expr]
  if empty? posList [report expr]
  report atPos but-first posList item (first poslist) expr
end

to-report append [list1 list2]
  if empty? list1 [report list2]
  report fput (first list1) (append (but-first list1) list2)
end

to-report selectProbilistically [charList numList]
  report item (chooseProbilistically numList) charList
end

to-report chooseProbilistically [numList]
  report findPos (random-float 1) cummulateList scaleList numList
end

to-report chooseReverseProbilistically [numList]
  if length numList = 1 [report 0]
  report findPos (random-float 1) cummulateList reverseProbList scaleList numList
end

to-report reverseProbList [numList]
  report map [1 - ?1] numList
end

to-report cummulateList [numList]
  report cummulateListR numList 0
end

to-report cummulateListR [numList cumm]
  if empty? numList [report []]
  let newCumm cumm + first numList
  report fput newCumm cummulateListR but-first numList newCumm
end

to-report scaleList [numLis]
  if empty? numLis [report numLis]
  let sumLis sum numLis
  if sumLis = 0 [report numLis]
  report map [?1 / sumLis] numLis
end

to-report findPos [vl numList]
  report findPosR vl numList 0
end

to-report findPosR [vl numList  ps]
  if empty? numList [report ps]
  if vl <= (first numList) [report ps]
  report findPosR vl but-first numList (1 + ps)
end

to-report freqOfIn [lis allList]
  report reduce [fput (numOfIn ?2 lis) ?1 ] (fput [] allList)
end  
  
to-report freqOf [lis]
  if empty? lis [report []]
  let sort-lis sort lis
  let red-lis sort remove-duplicates lis
  let op-lis red-lis
  let num-lis []
  let cnt 0
  foreach sort-lis [
    ifelse ? = first red-lis 
      [set cnt cnt + 1]
      [set num-lis fput cnt num-lis 
       set cnt 1
       set red-lis but-first red-lis]
  ]
  set num-lis fput cnt num-lis 
  report pair-list (reverse num-lis) op-lis
;;  report pair-list reverse num-lis red-lis
  ;;  report fput (list (numOfIn first lis lis) (first lis)) (freqOf remove first lis lis)
end

to-report freqRep [lis]
  report sort-by [first ?1 > first ?2] filter [first ? > 1] freqOf lis 
end

to-report numOfIn [itm lis]
  report length (filter [itm = ?] lis)
end

to-report patchesToDist [dist]
  if dist = 0 [report self]
  let patchList []
  foreach seq (-1 * dist) dist 1 [
    let xc ?
      foreach seq (-1 * dist) dist 1 [
        set patchList fput patch-at xc ? patchList
      ]
  ]
  report patch-set patchList
end

to-report individualsToDist [dist]
  report entities-on patchesToDist dist
end

to-report distBetween [x1 y1 x2 y2]
  report (max list abs (x1 - x2) abs (y1 - y2))
;;  report sqrt (((x1 - x2) ^ 2) + ((y1 - y2) ^ 2))
end

to-report seq [from upto stp]
  report n-values (1 + ceiling ((upto - from) / stp)) [from + ? * stp]
end

to-report safeDiv [numer denom]
  if denom = 0 and numer = 0 [report 1]
  if denom = 0 [report 0]
  report numer / denom
end  

;;to-report flip-bit [ps bitList]
;;  report replace-item ps bitList (1 - (item ps bitList))  
;;end


to showList [lis]
  foreach but-last lis [type ? type " "]
  print last lis
end


to-report is-divisor-of [num den] 
  report (0 = (num mod den))
end

to-report pair-list [lis1 lis2]
 report (map [list ?1 ?2] lis1 lis2)
end

to-report depth [lis]
  if not is-list? lis [report 0]
  if empty? lis [report 0]
  report 1 + max map [depth ?] lis
end

to-report empty-as
  report no-turtles
end

to-report exists [obj]
  if is-turtle-set? obj [report any? obj]
  report obj != nobody
end

to-report pick-at-random-from-list [lis]
  report item random length lis lis
end

to tv [str val]
  if trace? [output-print (word str "=" val)]
end

to-report normal-dist [x mn sd]
  report exp (-0.5 * ((x - mn) / sd) ^ 2) / (sd * sqrt (2 * pi))
end

to-report careful-item [ps lis str]
  let rs 0
  carefully 
    [set rs item ps lis] 
    [output-print (word "str" ": no position " ps " in: " lis)]
  report rs
end