Simulator_20260316-3_V8

Simulator_20260316-3_V8 preview image

1 collaborator

Tags

(This model has yet to be categorized with any tags)
Visible to everyone | Changeable by everyone
Model was written in NetLogo 3D 7.0.3 • Viewed 2 times • Downloaded 0 times • Run 0 times
Download the 'Simulator_20260316-3_V8' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)



WHAT IS IT?

This simulator models the co‑evolution of opinions, internal representations (memes), prevalence, influence, and network structure in a connected population of agents.
Each agent carries:

  • an opinion in [-1, +1]
  • a prevalence (0–99), representing the depth of its internal representations
  • an influence level (0–1)
  • meme quantities and meme weights
  • a meta‑type (structural / dynamic / none)
  • social links that evolve over time

The model integrates:

  • meme‑based opinion formation
  • targeted meme injection
  • endogenous and structural meta‑influencers
  • homophily‑based network rewiring
  • group effects
  • reward‑based reinforcement
  • exogenous events
  • CSV import/export of agent states and statistics

3D REPRESENTATION

Agents are mapped to:

  • X‑axis: opinion (−1 = left, +1 = right)
  • Y‑axis: prevalence (0–99)
  • Z‑axis: influence (0–1)

Colors:

  • Red: left‑leaning
  • Blue: right‑leaning
  • White: center
  • Yellow: meta‑influencers (structural or dynamic)

Links:

  • Green: same‑sign
  • Gray: opposite‑sign

HOW TO USE

  1. Choose population size with pop.
  2. Click Setup to initialize agents and networks.
  3. Click Go to run or pause.
  4. Use output, csv‑export, and csv‑mode to record results.
  5. Use infilevalues to reload a saved state.
  6. Use choice_iter to select which iteration to restore.

GENERAL CONTROLS

  • Setup: initialize agents, networks, memes, meta‑structure
  • Go: start/stop simulation
  • in_file: load simple-format agent states
  • infilevalues: load full agent states (Values CSV)
  • refresh: reset plots
  • cumulative: if OFF, resets counters each tick
  • output: None | Statistics | Values | File

POPULATION & ITERATIONS

  • pop: number of agents
  • nb_try: number of trials
  • max_iter: iterations per trial
  • threshold: majority threshold
  • choice_iter: iteration to restore when importing Values CSV

META‑INFLUENCERS (STRUCTURAL & DYNAMIC)

The model distinguishes two types of meta‑influencers.

Structural meta‑influencers

  • Assigned at setup
  • meta-influencers-selection: All / Left / Right
  • meta-influencers: % of population
  • prev-low / prev-high: eligibility
  • influence = 1
  • persistent
  • restored when importing Values CSV
  • yellow and counted in meta-agents
  • create meta-links
  • metablock prevents sign switching

Dynamic meta‑influencers

  • Emerge when influence rises to 1
  • yellow but not counted as structural
  • do not create structural meta-links
  • fully exported/imported via meta-type

Meta‑type variable

Each agent has:

  • structural
  • dynamic
  • none

Used for:

  • export/import
  • color restoration
  • meta-link behavior

SOCIAL NETWORK DYNAMICS

Links evolve through homophily and probabilistic rewiring.

  • link-removal-threshold
  • link-formation-threshold
  • prob
  • linksdown / linksup
  • bridge-prob
  • show-links?
  • linktick

Structural metas may create meta-links based on:

  • meta-min / meta-max / meta-links
  • meta-ok

OPINION & PREVALENCE DYNAMICS

Opinion adoption depends on:

  • prevalence-weight
  • polarization-factor
  • adoption-floor
  • noise
  • group effects
  • reward system
  • meme dynamics

Prevalence adapts through:

  • mod-prev
  • rate-mod

GROUP EFFECT

  • group-impact-mode: all or k-nearest
  • group-k
  • group-impact-weight
  • group-impact-alpha

Alpha interpretation:

  • <1: small clusters matter more
  • =1: linear
  • >1: only large aligned groups matter

REWARD MECHANISM

Successful influencers receive a temporary tx-bonus.

  • reward-step
  • reward-cap
  • reward-decay
  • reward-scope
  • reward-prev-delta

MEME-BASED REPRESENTATION

When use-memes? is ON, opinions and prevalence derive from meme stocks.

Meme quantities → Prevalence

  • meme-plus
  • meme-minus
  • prevalence = rescaled total quantity

Meme weights → Opinion

Opinion = (meme-plus-w − meme-minus-w) / (meme-plus-w + meme-minus-w)

Weighted transmission

Receivers gain:

  • meme quantity
  • meme weight proportional to quantity

Parameters:

  • meme-weight-mean
  • meme-weight-sd
  • meme-weight-min / max

Anti-leak & decay

  • meme-anti-leak
  • meme-decay

MEME INJECTION

Eligibility:

  • inject-lowmeme ≤ opinion ≤ inject-highmeme
  • inject-low-prev ≤ prevalence ≤ inject-high-prev

Parameters:

  • inject-prob-max
  • inject-sign
  • inject-amount
  • inject-weight
  • auto_inject?, inject-tick
  • repeat-inject?, inject-pace

EXOGENOUS EVENTS

Events shift:

  • opinion (event_size)
  • prevalence (prev_change)

Targeting:

  • memeset + toleft
  • or bounds: lowmeme / highmeme, low-prev / high-prev

Scheduling:

  • auto_event
  • event-init
  • repeat-event
  • event-pace
  • event-prob-max
  • event-meme-change?

CSV EXPORT

Two modes.

Statistics mode

Exports per tick:

  • mean/median opinion
  • median prevalence
  • median influence
  • left/right shares
  • link creation/removal
  • inversion rate
  • interaction counters
  • fractal indicators
  • ideologization indices

Values mode

Exports per agent:

  • try
  • tick
  • who
  • prevalence
  • opinion
  • influence
  • meme-plus
  • meme-minus
  • meme-plus-w
  • meme-minus-w
  • meta-type

CSV IMPORT (VALUES MODE)

Pipeline:

  1. Read CSV
  2. Store rows
  3. Select tick = choice_iter
  4. load-and-store-initial-state
  5. restore-initial-state
  6. Reconstruct:
    • opinions
    • prevalence
    • influence
    • meme stocks
    • meta-type
    • colors
    • meta-links

Ensures perfect reproducibility.


MONITORING INDICATORS

  1. Mean Meme Stock
  2. Meme Polarity Index
  3. Opinion–Meme Gap
    4a. Ideologization Index (meme-based)
    4b. Ideologization Index (opinion-based)
  4. Right Meme Polarization
  5. Left Meme Polarization
  6. Mean Meme-derived Opinion
  7. Meme Saturation (%)

PRESET: CAMPAIGN / RUMOR / POLARIZING SHOCK

A ready-to-run configuration illustrating:

  • baseline stabilization
  • repeated targeted shocks
  • meme accumulation
  • polarization
  • network segmentation

CONCEPTUAL INTERPRETATION

The model integrates:

  • cognitive depth
  • representational structure
  • behavioral stance
  • social reinforcement
  • structural elites
  • emergent influencers
  • network homophily
  • exogenous shocks
  • targeted diffusion

Allows exploration of:

  • polarization
  • ideological saturation
  • diffusion delays
  • nonlinear amplification
  • elite influence
  • cognitive vs behavioral ideologization

END OF INFO TAB


Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

extensions [ sound nw ]

globals [
  ;; core
  min-prevalence
  max-prevalence
  memes-per-change
  meta-influencers-right
  meta-influencers-left
  inject-tick tick-event
  iter change total inversion try major fractale
  ordonnee abscisse profondeur
  list_data file-in in_data repet_data 
  links-dead links-create meta-agents meta-links meta-create Interactions %Major
  initial-turtles-data  ;; Liste pour stocker l'état initial de toutes les tortues
  initial-tick-loaded   ;; Le tick qui a été chargé
  initial-turtles-data-copy  ;; Une copie séparée pour préserver l'original
  simple-initial-data  ;; Pour stocker les données initiales du format simple
  simple-import-mode   ;; Pour savoir si on est en mode simple
  file-imported?  ;; Indique si un fichier a été importé
  ;; CSV
  csv-file-stats
  csv-file-values
  csv-buffer
  csv-open?
  setup?
  ;; import Values CSV
  list_values_data
  values_file_in
  values_sep
  
  ;; Mode d'importation
  import-mode
  initial-tick-state

  ;; FRACTAL
  topological-dimension
  dynamic-dimension
  criticality-gap
  criticality-history
  box-sizes
  network-snapshots
  cascade-sizes
  last-cascade-id

  ;; CONSTELLATIONS
  constellation-1-size constellation-2-size constellation-3-size 
  constellation-4-size constellation-5-size
  constellation-1-opinion-avg constellation-2-opinion-avg 
  constellation-3-opinion-avg constellation-4-opinion-avg constellation-5-opinion-avg
  constellation-1-prev-avg constellation-2-prev-avg 
  constellation-3-prev-avg constellation-4-prev-avg constellation-5-prev-avg
  constellation-1-polarization constellation-2-polarization 
  constellation-3-polarization constellation-4-polarization constellation-5-polarization
  turnover-global turnover-c1 turnover-c2 turnover-c3 turnover-c4 turnover-c5
  opinion-entropy
  center-volatility
  prev-constellation-list
  last-center-opinion
  c-opinion-extreme
  c-opinion-moderate
  c-prevalence-high
  c-prevalence-low

  ;; LYAPUNOV
  lyapunov-exponent
  perturbation-history
  reference-trajectory
  perturbed-trajectory
  divergence-history
]

turtles-own [
  meta-type   ;; "structural" ou "dynamic"
  opinion
  prevalence
  agent-type
  influence
  opinion-previous
  influence-previous
  x3d y3d z3d
  meme-plus
  meme-minus
  meme-plus-w
  meme-minus-w
  old-opinion
  proposed-opinion
  tx-bonus
  cascade-id
  constellation-prev
]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LOCALE / FORMAT HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report col-sep
  ifelse locale-format = "FR" [ report ";" ] [ report "," ]
end 

to-report replace-all [s old new]
  let out s
  while [ position old out != false ] [
    let i position old out
    set out (word (substring out 0 i) new (substring out (i + length old) (length out)))
  ]
  report out
end 

to-report fmt [x]
  if x = nobody [ report "" ]
  if not is-number? x [ report (word x) ]
  let s (word "" x)
  if locale-format = "FR" [
    set s replace-all s "." ","
  ]
  report s
end 

to-report join-cols [lst]
  let sep col-sep
  let out ""
  foreach lst [ val ->
    let s (word "" val)
    set out ifelse-value (out = "")
      [ s ]
      [ (word out sep s) ]
  ]
  report out
end 

to-report split-by [s sep]
  let parts []
  let rest s
  while [ position sep rest != false ] [
    let i position sep rest
    set parts lput (substring rest 0 i) parts
    set rest substring rest (i + length sep) (length rest)
  ]
  set parts lput rest parts
  report parts
end 

to-report to-number-locale [s sep]
  if s = "" [ report 0 ]
  let x s
  if sep = ";" [
    set x replace-all x "," "."
  ]
  set x replace-all x " " ""
  report read-from-string x
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CONFIG IMPORT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to import-config-from-stats-csv
  let f user-file
  if f = false [ stop ]
  file-close-all
  let cfg-sep ";"
  carefully [
    file-open f
    while [not file-at-end?] [
      let line file-read-line
      if line != "" [
        if (length line >= 7) [
          if (substring line 0 7 = "CONFIG,") [ set cfg-sep "," ]
          if (substring line 0 7 = "CONFIG;") [ set cfg-sep ";" ]
        ]
        if (length line >= 12) [
          if (substring line 0 12 = "CONFIG_BEGIN,") [ set cfg-sep "," ]
          if (substring line 0 12 = "CONFIG_BEGIN;") [ set cfg-sep ";" ]
        ]
        if (length line >= 10) and (substring line 0 10 = "CONFIG_END") [
          file-close
          user-message "Configuration loaded from Statistics CSV. Press SETUP to rebuild."
          stop
        ]
        let prefix (word "CONFIG" cfg-sep)
        if (length line >= length prefix) and (substring line 0 (length prefix) = prefix) [
          let cols split-config-line line cfg-sep
          if length cols >= 3 [
            let p item 1 cols
            let v item 2 cols
            apply-config-param p v
          ]
        ]
      ]
    ]
    file-close
    user-message "No CONFIG_END marker found. Config rows applied."
  ] [
    file-close-all
    user-message "Config import error: could not read or parse the file."
  ]
end 

to-report split-config-line [s sep]
  let parts []
  let rest s
  while [ position sep rest != false ] [
    let i position sep rest
    set parts lput (substring rest 0 i) parts
    set rest substring rest (i + length sep) (length rest)
  ]
  set parts lput rest parts
  report parts
end 

to-report trim-spaces [s]
  let out s
  while [ (length out > 0) and (substring out 0 1 = " ") ] [
    set out substring out 1 (length out)
  ]
  while [ (length out > 0) and (substring out (length out - 1) (length out) = " ") ] [
    set out substring out 0 (length out - 1)
  ]
  report out
end 

to-report maybe-number-fr [s]
  let x trim-spaces s
  if x = "" [ report nobody ]
  set x replace-all x " " ""
  set x replace-all x "," "."
  let r nobody
  carefully [
    set r read-from-string x
  ] [
    set r nobody
  ]
  if is-number? r [ report r ]
  report nobody
end 

to apply-config-param [param value]
  let p trim-spaces param
  let v trim-spaces value
  if p = "meta-type-definition" [ stop ]
  if v = "true"  [ run (word "set " p " true")  stop ]
  if v = "false" [ run (word "set " p " false") stop ]
  let n maybe-number-fr v
  if n != nobody [
    run (word "set " p " " n)
    stop
  ]
  let vv replace-all v "\"" "'"
  run (word "set " p " \"" vv "\"")
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SETUP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to setup
  clear-all
  set file-imported? false
  set repet_data false
  set iter 0
  set min-prevalence 0
  set max-prevalence 99
  set-default-shape turtles "person"
  set try 1
  set inject-tick inject-base
  set major 0
  set setup? true

  if not is-string? locale-format [ set locale-format "FR" ]
  if (locale-format != "FR" and locale-format != "EN") [ set locale-format "FR" ]

  if not is-number? event-init [ set event-init 50 ]
  set tick-event event-init

  set links-dead 0
  set links-create 0
  set meta-create 0
  set meta-agents 0
  set change 0
  set total 0
  set inversion 0
  set fractale 0

  if (vary-influence = true) or (meta-ok = true) [ set meta-links meta-min ]

  if not is-boolean? csv-export [ set csv-export false ]
  if (not is-string? csv-basename) or (csv-basename = "") [ set csv-basename "run" ]
  if not is-string? csv-mode [ set csv-mode "Statistics" ]
  if (csv-mode != "Statistics" and csv-mode != "Values") [
    set csv-mode "Statistics"
  ]
  if not is-number? csv-values-step  [ set csv-values-step 10 ]
  if csv-values-step < 1 [ set csv-values-step 1 ]
  if not is-number? csv-values-start [ set csv-values-start 0 ]
  if csv-values-start < 0 [ set csv-values-start 0 ]

  set csv-file-stats ""
  set csv-file-values ""
  set csv-buffer []
  set csv-open? false

  set list_values_data []
  set values_file_in false
  set values_sep ";"
  set import-mode "simple"
  set initial-tick-state 1

  if not is-boolean? inject-metas-only [ set inject-metas-only false ]

  if (not is-string? group-impact-mode) [ set group-impact-mode "all" ]
  if (not is-number? group-k) [ set group-k 10 ]
  if (not is-number? group-impact-weight) [ set group-impact-weight 0.5 ]
  if (not is-number? group-impact-alpha) [ set group-impact-alpha 1.0 ]

  if not is-boolean? show-links [ set show-links false ]
  if not is-boolean? metablock  [ set metablock false ]

  if (not is-number? prevalence-weight) [ set prevalence-weight 1.5 ]
  if (not is-number? adoption-floor)    [ set adoption-floor 0.02 ]
  if (not is-number? bridge-prob)       [ set bridge-prob 0.10 ]

  if not is-number? reward-step       [ set reward-step 0.05 ]
  if not is-number? reward-cap        [ set reward-cap  0.50 ]
  if not is-string? reward-scope      [ set reward-scope "both" ]
  if not is-number? reward-prev-delta [ set reward-prev-delta 0 ]
  if not is-number? reward-decay      [ set reward-decay 0 ]

  if not is-boolean? use-memes?    [ set use-memes? false ]
  if not is-number? meme-max       [ set meme-max 100 ]
  if not is-number? meme-gain      [ set meme-gain 1.0 ]
  if not is-number? meme-anti-leak [ set meme-anti-leak 0.0 ]
  if not is-number? meme-decay     [ set meme-decay 0.0 ]

  if not is-number? meme-weight-mean [ set meme-weight-mean 1.0 ]
  if not is-number? meme-weight-sd   [ set meme-weight-sd 0.0 ]
  if not is-number? meme-weight-min  [ set meme-weight-min 0.05 ]
  if not is-number? meme-weight-max  [ set meme-weight-max 5.0 ]

  if not is-boolean? auto_inject?   [ set auto_inject? false ]
  if not is-boolean? repeat-inject? [ set repeat-inject? false ]
  if not is-number? inject-tick     [ set inject-tick 50 ]
  if not is-number? inject-pace     [ set inject-pace 50 ]

  if not is-string? inject-sign     [ set inject-sign "plus" ]
  if not is-number? inject-amount   [ set inject-amount 1 ]
  if not is-number? inject-weight   [ set inject-weight 1.0 ]
  if not is-number? inject-prob-max [ set inject-prob-max 1.0 ]

  if not is-number? inject-low_meme  [ set inject-low_meme -1.0 ]
  if not is-number? inject-high_meme [ set inject-high_meme  1.0 ]
  if not is-number? inject-low-prev  [ set inject-low-prev  0.0 ]
  if not is-number? inject-high-prev [ set inject-high-prev 99.0 ]

  set-background-black

  set topological-dimension 0
  set dynamic-dimension 0
  set criticality-gap 0
  set criticality-history []
  set box-sizes [0.5 0.25 0.125 0.0625 0.03125 0.015625]
  set network-snapshots []
  set cascade-sizes []
  set last-cascade-id 0

  set c-opinion-extreme 0.6
  set c-opinion-moderate 0.2
  set c-prevalence-high 50
  set c-prevalence-low 30

  set constellation-1-size 0
  set constellation-2-size 0
  set constellation-3-size 0
  set constellation-4-size 0
  set constellation-5-size 0

  set constellation-1-opinion-avg 0
  set constellation-2-opinion-avg 0
  set constellation-3-opinion-avg 0
  set constellation-4-opinion-avg 0
  set constellation-5-opinion-avg 0

  set constellation-1-prev-avg 0
  set constellation-2-prev-avg 0
  set constellation-3-prev-avg 0
  set constellation-4-prev-avg 0
  set constellation-5-prev-avg 0

  set constellation-1-polarization 0
  set constellation-2-polarization 0
  set constellation-3-polarization 0
  set constellation-4-polarization 0
  set constellation-5-polarization 0

  set turnover-global 0
  set turnover-c1 0
  set turnover-c2 0
  set turnover-c3 0
  set turnover-c4 0
  set turnover-c5 0

  set opinion-entropy 0
  set center-volatility 0
  set last-center-opinion 0
  set prev-constellation-list []

  set lyapunov-exponent 0
  set perturbation-history []
  set divergence-history []
  set reference-trajectory []
  set perturbed-trajectory []

  create
  output-headers

  ask turtles [
    set constellation-prev get-constellation self
    set prev-constellation-list lput (list who 0) prev-constellation-list
  ]

  capture-network-snapshot
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CREATE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to create
    if not file-imported? [create-turtles pop / 2 [
    set agent-type "Right side"
    set opinion random-float 1
    set color blue
    set prevalence random-float (opinion * 100)
    set influence random-float 1
    set opinion-previous opinion
    set influence-previous influence
    set tx-bonus 0
    set cascade-id 0
    set constellation-prev 0
    set meta-type "none" 
    init-memes-from-state
    update-3d self
  ]

  create-turtles pop / 2 [
    set agent-type "Left side"
    set opinion (random-float 1 - 1)
    set color red
    set prevalence random-float (abs opinion * 100)
    set influence random-float 1
    set opinion-previous opinion
    set influence-previous influence
    set tx-bonus 0
    set cascade-id 0
    set constellation-prev 0
    set meta-type "none"   
    init-memes-from-state
    update-3d self
  ]]

  reset-ticks
  influencers

  set total 0
  set change 0
  set Interactions 0
  set %Major 0

  update-networks
  recolor-links
  apply-link-visibility
end 

to output-headers
  if output = "Statistics" [
    output-print join-cols (list
      "Try" "Iter"
      "Global Opinion"
      "Right side Opinion" "Left side Opinion"
      "Right side Prevalence" "Left side Prevalence"
      "Right side Influence" "Left side Influence"
      "Left %" "Right %"
      "Links-Remove" "Links-Create"
      "Inversion %" "change" "total" "fractal"
    )
  ]
  if output = "Values" [
    output-print join-cols (list
      "Try" "Ticks" "Agents"
      "Prevalence" "Opinion" "Influence"
      "meme plus" "meme minus"
      "meme plus w" "meme minus w"
    )
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; META-INFLUENCERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to influencers
  if meta-mode = "Pourcent" [
    if meta-influencers-selection = "All" [
      let k round (count turtles * meta-influencers / 100)
      let candidates turtles with [(prevalence >= prev-low and prevalence <= prev-high)]
      if k > 0 and any? candidates [
        let n-to-take min (list k count candidates)
        ask up-to-n-of n-to-take candidates [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
          set meta-type "structural"
        ]
      ]
    ]

    if meta-influencers-selection = "Right side" [
      let k round (count turtles * meta-influencers / 100)
      let candidates turtles with [opinion > 0 and (prevalence >= prev-low and prevalence <= prev-high)]
      if k > 0 and any? candidates [
        let n-to-take min (list k count candidates)
        ask up-to-n-of n-to-take candidates [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
          set meta-type "structural"
        ]
      ]
    ]

    if meta-influencers-selection = "Left side" [
      let k round (count turtles * meta-influencers / 100)
      let candidates turtles with [opinion < 0 and (prevalence >= prev-low and prevalence <= prev-high)]
      if k > 0 and any? candidates [
        let n-to-take min (list k count candidates)
        ask up-to-n-of n-to-take candidates [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
          set meta-type "structural"
        ]
      ]
    ]
  ]

  if meta-mode = "Nombre" [
    if meta-influencers-selection = "All" [
      let k meta-influencers
      let candidates turtles with [(prevalence >= prev-low and prevalence <= prev-high)]
      if k > 0 and any? candidates [
        let n-to-take min (list k count candidates)
        ask up-to-n-of n-to-take candidates [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
          set meta-type "structural"
        ]
      ]
    ]

    if meta-influencers-selection = "Right side" [
      let candidates turtles with [opinion > 0 and (prevalence >= prev-low and prevalence <= prev-high)]
      let k meta-influencers
      if k > 0 and any? candidates [
        let n-to-take min (list k count candidates)
        ask up-to-n-of n-to-take candidates [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
          set meta-type "structural"
        ]
      ]
    ]

    if meta-influencers-selection = "Left side" [
      let candidates turtles with [opinion < 0 and (prevalence >= prev-low and prevalence <= prev-high)]
      let k meta-influencers
      if k > 0 and any? candidates [
        let n-to-take min (list k count candidates)
        ask up-to-n-of n-to-take candidates [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
          set meta-type "structural"
        ]
      ]
    ]
  ]
end 

to-report meta?
  report (color = yellow) or (influence = 1)
end 

to maybe-set-opinion [ new-op ]
  let old-op opinion
  let bounded-op max list -1 min list 1 new-op
  if metablock and meta? and (sign old-op != sign bounded-op) [
    let mag max list (abs old-op) (abs bounded-op)
    set opinion (sign old-op) * mag
    stop
  ]
  set opinion bounded-op
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CSV
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report csv-filename [mode-tag]
  report (word csv-basename "-" try "-" mode-tag "-" locale-format ".csv")
end 

to csv-begin
  if not csv-export [ stop ]
  set csv-buffer []
  set csv-open? true
  if csv-mode = "Statistics" [
    set csv-file-stats csv-filename "stats"
    if file-exists? csv-file-stats [
      carefully [ file-delete csv-file-stats ] [
        set csv-file-stats (word csv-file-stats "_locked_" (random 1000000))
      ]
    ]
    set csv-buffer lput (join-cols (list
    "try" "iter" "tick"
    "left_pct" "right_pct"
    "avg_opinion"
    "med_op_right" "med_op_left"
    "med_prev_right" "med_prev_left"
    "med_infl_right" "med_infl_left"
    "links_remove" "links_create" 
    "bridge_links"
    "inversion_pct" "change" "total" "fractal" "major"
    "interactions_per_iter" "majority_pct" "interactions_per_inversion"
    "meta_links" "meta_agents"
    "mean_prevalence" "median_prevalence" "median_opinion"
    "mean_abs_opinion"
    "mean_meme_stock" "mean_meme_derived_opinion"
    "mean_polarity_index" "meme_saturation_pct"
    "right_meme_polarization" "left_meme_polarization"
    "opinion_meme_gap"
    "ideologization_index"
    "ideologization_opinion_based"
    "topological_dim" "dynamic_dim" "criticality_gap" "Status"
    "c1_size" "c2_size" "c3_size" "c4_size" "c5_size"
    "c1_opinion_avg" "c2_opinion_avg" "c3_opinion_avg" "c4_opinion_avg" "c5_opinion_avg"
    "c1_prev_avg" "c2_prev_avg" "c3_prev_avg" "c4_prev_avg" "c5_prev_avg"
    "c1_polarization" "c2_polarization" "c3_polarization" "c4_polarization" "c5_polarization"
    "turnover_global" "turnover_c1" "turnover_c2" "turnover_c3" "turnover_c4" "turnover_c5"
    "opinion_entropy" "center_volatility" "regime_code"
    "lyapunov_exponent")) csv-buffer
  ]
  if csv-mode = "Values" [
    set csv-file-values csv-filename "values"
    if file-exists? csv-file-values [
      carefully [ file-delete csv-file-values ] [
        set csv-file-values (word csv-file-values "_locked_" (random 1000000))
      ]
    ]
    set csv-buffer lput (join-cols (list
      "try" "tick" "agent"
      "prevalence" "opinion" "influence"
      "meme_plus" "meme_minus"
      "meme_plus_w" "meme_minus_w"
       "meta-type" 
    )) csv-buffer
  ]
end 

to ensure-csv-ready
  if not csv-export [ stop ]
  if not csv-open? [ csv-begin ]
end 

to csv-row-statistics
  let sys-status system-status
  let avg-opinion mean [opinion] of turtles
  let opR safe-median (turtles with [opinion >= 0]) "opinion"
  let opL safe-median (turtles with [opinion < 0])  "opinion"
  let prevR (safe-median (turtles with [opinion >= 0]) "prevalence") / 100
  let prevL (safe-median (turtles with [opinion < 0])  "prevalence") / 100
  let inflR safe-median (turtles with [opinion >= 0]) "influence"
  let inflL safe-median (turtles with [opinion < 0])  "influence"
  let leftpct  (count turtles with [opinion < 0])  / (pop / 100)
  let rightpct (count turtles with [opinion >= 0]) / (pop / 100)
  let bridge_links count links with [ (sign [opinion] of end1) != (sign [opinion] of end2) ]
  let interactions-per-iter ifelse-value (iter > 0) [ total / iter ] [ 0 ]
  let majority-pct %Major
  let interactions-per-inversion ifelse-value (change > 0) [ total / change ] [ 0 ]
  let mean-prevalence ifelse-value (any? turtles) [ mean [prevalence] of turtles ] [ 0 ]
  let median-prevalence safe-median turtles "prevalence"
  let median-opinion safe-median turtles "opinion"
  let mean-abs-opinion ifelse-value (any? turtles) [ mean [abs opinion] of turtles ] [ 0 ]
  let mean-meme-stock ifelse-value (any? turtles) [ mean [meme-plus + meme-minus] of turtles ] [ 0 ]
  let mean-meme-derived-opinion ifelse-value (any? turtles) [
    mean [
      ifelse-value ((meme-plus-w + meme-minus-w) > 0)
        [ (meme-plus-w - meme-minus-w) / (meme-plus-w + meme-minus-w) ]
        [ 0 ]
    ] of turtles
  ] [ 0 ]
  let mean-pol-index mean-polarity-index
  let meme-sat meme-saturation-pct
  let right-den sum [meme-plus + meme-minus] of turtles with [opinion >= 0]
  let right-num (sum [meme-plus] of turtles with [opinion >= 0]) - (sum [meme-minus] of turtles with [opinion >= 0])
  let right-meme-pol ifelse-value (right-den > 0) [ right-num / right-den ] [ 0 ]
  let left-den sum [meme-plus + meme-minus] of turtles with [opinion < 0]
  let left-num (sum [meme-plus] of turtles with [opinion < 0]) - (sum [meme-minus] of turtles with [opinion < 0])
  let left-meme-pol ifelse-value (left-den > 0) [ left-num / left-den ] [ 0 ]
  let opinion-meme-gap ifelse-value (any? turtles) [
    mean [
      abs (opinion - (ifelse-value ((meme-plus-w + meme-minus-w) > 0)
        [ (meme-plus-w - meme-minus-w) / (meme-plus-w + meme-minus-w) ]
        [ 0 ]))
    ] of turtles
  ] [ 0 ]
  let ideologization-index ifelse-value (any? turtles) [ ideologization-meme-based ] [ 0 ]
  let ideologization-opinion-based-val ifelse-value (any? turtles) [ ideologization-opinion-based ] [ 0 ]
  let d_top ifelse-value (topological-dimension > 0) [ topological-dimension ] [ 0 ]
  let d_dyn ifelse-value (dynamic-dimension > 0) [ dynamic-dimension ] [ 0 ]
  let c_gap ifelse-value (criticality-gap > 0) [ criticality-gap ] [ 0 ]
  let regime-code system-regime-code

  set csv-buffer lput (join-cols (list
    fmt try
    fmt iter
    fmt ticks
    fmt leftpct
    fmt rightpct
    fmt avg-opinion
    fmt opR
    fmt opL
    fmt prevR
    fmt prevL
    fmt inflR
    fmt inflL
    fmt links-dead
    fmt links-create
    fmt bridge_links
    fmt inversion
    fmt change
    fmt total
    fmt fractale
    fmt major
    fmt interactions-per-iter
    fmt majority-pct
    fmt interactions-per-inversion
    fmt meta-links
    fmt meta-agents
    fmt mean-prevalence
    fmt median-prevalence
    fmt median-opinion
    fmt mean-abs-opinion
    fmt mean-meme-stock
    fmt mean-meme-derived-opinion
    fmt mean-pol-index
    fmt meme-sat
    fmt right-meme-pol
    fmt left-meme-pol
    fmt opinion-meme-gap
    fmt ideologization-index
    fmt ideologization-opinion-based-val
    fmt d_top
    fmt d_dyn
    fmt c_gap
    fmt sys-status
    fmt constellation-1-size
    fmt constellation-2-size
    fmt constellation-3-size
    fmt constellation-4-size
    fmt constellation-5-size
    fmt constellation-1-opinion-avg
    fmt constellation-2-opinion-avg
    fmt constellation-3-opinion-avg
    fmt constellation-4-opinion-avg
    fmt constellation-5-opinion-avg
    fmt constellation-1-prev-avg
    fmt constellation-2-prev-avg
    fmt constellation-3-prev-avg
    fmt constellation-4-prev-avg
    fmt constellation-5-prev-avg
    fmt constellation-1-polarization
    fmt constellation-2-polarization
    fmt constellation-3-polarization
    fmt constellation-4-polarization
    fmt constellation-5-polarization
    fmt turnover-global
    fmt turnover-c1
    fmt turnover-c2
    fmt turnover-c3
    fmt turnover-c4
    fmt turnover-c5
    fmt opinion-entropy
    fmt center-volatility
    fmt regime-code
    fmt lyapunov-exponent
  )) csv-buffer
end 

to csv-add-config-snapshot
  if not csv-export [ stop ]
  if csv-mode != "Statistics" [ stop ]
  if not csv-open? [ stop ]
  set csv-buffer lput "" csv-buffer
  set csv-buffer lput (join-cols (list "CONFIG_BEGIN" (word "try=" try) (word "last_tick=" ticks))) csv-buffer
  let rows (list
    (list "pop" pop)
    (list "nb_try" nb_try)
    (list "max_iter" max_iter)
    (list "threshold" threshold)
    (list "cumulative" cumulative)
    (list "refresh" refresh)
    (list "output" output)
    (list "locale-format" locale-format)
    (list "csv-basename" csv-basename)
    (list "csv-mode" csv-mode)
    (list "csv-values-start" csv-values-start)
    (list "csv-values-step" csv-values-step)
    (list "network" network)
    (list "link-removal-threshold" link-removal-threshold)
    (list "link-formation-threshold" link-formation-threshold)
    (list "prob" prob)
    (list "linksdown" linksdown)
    (list "linksup" linksup)
    (list "bridge-prob" bridge-prob)
    (list "show-links" show-links)
    (list "linktick" linktick)
    (list "polarization-factor" polarization-factor)
    (list "prevalence-weight" prevalence-weight)
    (list "adoption-floor" adoption-floor)
    (list "noise" noise)
    (list "mode_prev" mode_prev)
    (list "rate-mod" rate-mod)
    (list "rate-infl" rate-infl)
    (list "group-impact-mode" group-impact-mode)
    (list "group-k" group-k)
    (list "group-impact-weight" group-impact-weight)
    (list "group-impact-alpha" group-impact-alpha)
    (list "reward-step" reward-step)
    (list "reward-cap" reward-cap)
    (list "reward-scope" reward-scope)
    (list "reward-prev-delta" reward-prev-delta)
    (list "reward-decay" reward-decay)
    (list "meta-ok" meta-ok)
    (list "meta-mode" meta-mode)
    (list "meta-influencers-selection" meta-influencers-selection)
    (list "meta-influencers" meta-influencers)
    (list "prev-low" prev-low)
    (list "prev-high" prev-high)
    (list "meta-min" meta-min)
    (list "meta-max" meta-max)
    (list "meta-links" meta-links)
    (list "meta-type-definition" "structural/dynamic/none")
    (list "metablock" metablock)
    (list "vary-influence" vary-influence)
    (list "auto_event" auto_event)
    (list "repeat_event" repeat_event)
    (list "event-init" event-init)
    (list "event-pace" event-pace)
    (list "event-prob-max" event-prob-max)
    (list "event_size" event_size)
    (list "prev_change" prev_change)
    (list "meme_set" meme_set)
    (list "to_left" to_left)
    (list "low_meme" low_meme)
    (list "high_meme" high_meme)
    (list "low-prev" low-prev)
    (list "high-prev" high-prev)
    (list "use-memes?" use-memes?)
    (list "meme-max" meme-max)
    (list "meme-gain" meme-gain)
    (list "meme-anti-leak" meme-anti-leak)
    (list "meme-decay" meme-decay)
    (list "meme-weight-mean" meme-weight-mean)
    (list "meme-weight-sd" meme-weight-sd)
    (list "meme-weight-min" meme-weight-min)
    (list "meme-weight-max" meme-weight-max)
    (list "auto_inject?" auto_inject?)
    (list "repeat-inject?" repeat-inject?)
    (list "inject-metas-only" inject-metas-only)
    (list "inject-tick" inject-tick)
    (list "inject-pace" inject-pace)
    (list "inject-sign" inject-sign)
    (list "inject-amount" inject-amount)
    (list "inject-weight" inject-weight)
    (list "inject-prob-max" inject-prob-max)
    (list "inject-low_meme" inject-low_meme)
    (list "inject-high_meme" inject-high_meme)
    (list "inject-low-prev" inject-low-prev)
    (list "inject-high-prev" inject-high-prev)
    (list "c-opinion-extreme" c-opinion-extreme)
    (list "c-opinion-moderate" c-opinion-moderate)
    (list "c-prevalence-high" c-prevalence-high)
    (list "c-prevalence-low" c-prevalence-low)
  )
  foreach rows [ r ->
    let k item 0 r
    let v item 1 r
    set csv-buffer lput (join-cols (list "CONFIG" (word k) (fmt v))) csv-buffer
  ]
  set csv-buffer lput (join-cols (list "CONFIG_END" (word "try=" try) "")) csv-buffer
end 

to csv-row-values
  if ticks < csv-values-start [ stop ]
  if (ticks mod csv-values-step) != 0 [ stop ]
  foreach sort turtles [ t ->
    set csv-buffer lput (join-cols (list
      fmt try
      fmt ticks
      fmt [who] of t
      fmt [prevalence] of t
      fmt [opinion] of t
      fmt [influence] of t
      fmt [meme-plus] of t
      fmt [meme-minus] of t
      fmt [meme-plus-w] of t
      fmt [meme-minus-w] of t
      fmt [meta-type] of t
    )) csv-buffer
  ]
end 

to csv-flush
  if empty? csv-buffer [ stop ]
  file-close-all
  let target ""
  if csv-mode = "Statistics" [ set target csv-file-stats ]
  if csv-mode = "Values"     [ set target csv-file-values ]
  file-open target
  foreach csv-buffer [ line -> file-print line ]
  file-close
  set csv-buffer []
end 

to csv-end
  if csv-open? [ csv-flush ]
  file-close-all
  set csv-buffer []
  set csv-open? false
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GO - VERSION CORRIGÉE AVEC ENCHAÎNEMENT AUTOMATIQUE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GO - Version avec enchaînement automatique des essais
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to go
  ;; Vérifier s'il y a des tortues
  if not any? turtles or count turtles != pop or setup? = 0 [
    user-message "Please click SETUP first to create the population!"
    stop
  ]
  
  ifelse (iter < max_iter) [
    ;; ========================================================================
    ;; DÉROULEMENT D'UN ESSAI
    ;; ========================================================================
    
    ;; Initialisation CSV
    if csv-export [ ensure-csv-ready ]
    if ticks mod 500 = 0 [ diagnose-system ]

    ;; Mise à jour des statistiques
    if iter > 0 [ set Interactions (total / iter) ]
    if iter > 0 [ set %Major (major / iter * 100) ]
    set iter iter + 1
    set meta-create 0

    ;; Événements
    if auto_event [
      if (iter = tick-event) [
        event
        if repeat_event [
          set tick-event (tick-event + event-pace)
        ]
      ]
    ]

    ;; Injection de mèmes
    if auto_inject? [ 
      if (iter = inject-tick) [
        inject-memes
        if repeat-inject? [ 
          set inject-tick (inject-tick + inject-pace)
        ]
      ]
    ]

    ;; Mise à jour des métriques
    if meta-ok = true [ meta ]
    update-opinions
    if network = true [ update-networks ]
    recolor-links
    apply-link-visibility
    capture-network-snapshot

    ;; Calculs périodiques
    if ticks mod 100 = 0 and ticks > 0 [
      compute-fractal-dimensions
      if ticks mod 500 = 0 [
        output-print (word "SYSTEM STATUS at tick " ticks ": " system-status)
      ]
      compute-lyapunov-exponent
    ]

    ;; Suivi des perturbations
    if ticks = 1 [ initialize-perturbation ]
    if ticks > 1 [ update-perturbation ]

    ;; Mise à jour des constellations
    update-constellations

    ;; Sortie statistiques
    if output = "Statistics" [
      let avg-opinion mean [opinion] of turtles
      let positive-opinion safe-median (turtles with [opinion >= 0]) "opinion"
      let negative-opinion safe-median (turtles with [opinion < 0])  "opinion"
      let positive-prevalence (safe-median (turtles with [opinion >= 0]) "prevalence") / 100
      let negative-prevalence (safe-median (turtles with [opinion < 0])  "prevalence") / 100
      let positive-influence safe-median (turtles with [opinion >= 0]) "influence"
      let negative-influence safe-median (turtles with [opinion < 0])  "influence"
      let Left%  (count turtles with [opinion < 0])  / (pop / 100)
      let Right% (count turtles with [opinion >= 0]) / (pop / 100)
      let ti iter

      output-print join-cols (list
        fmt try
        fmt ti
        fmt avg-opinion
        fmt positive-opinion
        fmt negative-opinion
        fmt positive-prevalence
        fmt negative-prevalence
        fmt positive-influence
        fmt negative-influence
        fmt Left%
        fmt Right%
        fmt links-dead
        fmt links-create
        fmt inversion
        fmt change
        fmt total
        fmt fractale
      )
    ]

    ;; Avancer le temps
    tick

    ;; Mise à jour des métriques fractales
    ifelse use-memes? [
      if (change > 1 and iter > 1) [ set fractale (ln total / ln change) ]
    ] [
      if (change > 1 and total > 1) [ set fractale (ln total) / (ln change) ]
    ]

    if (cumulative = false) [
      set change 0
      set total 0
    ]

    colorer

    if (refresh = true) [
      if ticks > 200 [ reset-ticks clear-plot ]
    ]

    if threshold <= (count turtles with [opinion > 0]) / (pop / 100) [
      set major major + 1
    ]

    ;; Écriture CSV
    if csv-export [
      if csv-mode = "Statistics" [ csv-row-statistics ]
      if csv-mode = "Values"     [ csv-row-values ]
    ]

    ;; ========================================================================
    ;; FIN DE L'ESSAI EN COURS
    ;; ========================================================================
  ] [
    ifelse (try < nb_try) [
      ;; ======================================================================
      ;; PRÉPARATION DU PROCHAIN ESSAI
      ;; ======================================================================
      
      ;; TUER LES TURTLES IMMÉDIATEMENT
      clear-turtles
      clear-links
      
      ;; Sauvegarde CSV si nécessaire
      if csv-export [
        if csv-mode = "Statistics" [ csv-add-config-snapshot ]
        csv-end
      ]

      ;; Réinitialisation des variables globales
      set try try + 1
      set major 0
      clear-turtles
      clear-plot
      set change 0
      set total 0
      set fractale 0
      set meta-links meta-min
      set iter 0
      set links-create 0
      set links-dead 0
      set meta-create 0
      set meta-agents 0
      set min-prevalence 0
      set max-prevalence 99
      set tick-event event-init
      set inject-tick inject-base

   ;; Rechargement des données selon le mode d'importation
      if (repet_data = true) [
        if (import-mode = "values") [
          restore-initial-state
          reset-ticks
          ;; NE PAS appeler go ici - le bouton Forever s'en charge
        ]
        if (import-mode = "simple") [
          data-simple
          reset-ticks
          ;; NE PAS appeler go ici - le bouton Forever s'en charge
        ]
      ]

      ;; Création d'une nouvelle population aléatoire (seulement si pas de fichier importé)
      if not file-imported? [
        create
        reset-ticks
      ]

      ;; Création d'une nouvelle population aléatoire
      ;;create
      ;;reset-ticks
      ;;go    ;; <<< LANCEMENT AUTOMATIQUE DU PROCHAIN ESSAI

      ;; ======================================================================
      ;; FIN DE TOUS LES ESSAIS
      ;; ======================================================================
    ] [
      if csv-export [
        if csv-mode = "Statistics" [ csv-add-config-snapshot ]
        csv-end
      ]
      sound:play-note "Tubular Bells" 60 64 1
      stop
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DATA IMPORT - VERSIONS CORRIGÉES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to in_file
  if setup? = 0 [user-message "Please click SETUP first before loading file!"
    stop]
  in_file_simple
end 

;; CORRECTION de in_file_simple

to in_file_simple
  carefully [
    set file-in user-file
    if (file-in != false) [
      set list_data []
      file-open file-in
      while [not file-at-end?] [
        set list_data sentence list_data (list (list file-read file-read file-read file-read))
      ]
      file-close
      
      ;; Stocker une copie des données initiales
      set simple-initial-data []
      foreach list_data [ row ->
        set simple-initial-data lput (copy-list row) simple-initial-data
      ]
      
      user-message (word "File uploaded (simple format)! " length list_data " lines loaded.")
      set import-mode "simple"
      set in_data true
      set repet_data true
    ]
  ] [
    user-message "File read error"
  ]
  
  set choice_iter 0
  data-simple
  set file-imported? true
end 

;; NOUVELLE PROCÉDURE pour charger et stocker l'état initial
;; CORRECTION de load-and-store-initial-state
;; CORRECTION de load-and-store-initial-state pour s'assurer que les données sont correctes

;; MODIFICATION de load-and-store-initial-state pour vérifier les données chargées
;; CORRECTION de load-and-store-initial-state
;; CORRECTION de load-and-store-initial-state avec copie profonde

to load-and-store-initial-state
  let tick-to-load initial-tick-loaded
  
  let initial-rows []
  
  foreach list_values_data [ ligne ->
    if is-list? ligne and length ligne >= 11 [
      let tick-courant to-number-locale (item 1 ligne) values_sep
      if tick-courant = tick-to-load [
        set initial-rows lput ligne initial-rows
      ]
    ]
  ]
  
  if empty? initial-rows [
    user-message (word "No data found for tick " tick-to-load " in the file!")
    stop
  ]
  
  ;; Trier par agent ID
  set initial-rows sort-by [ [a b] ->
    (to-number-locale (item 2 a) values_sep) < (to-number-locale (item 2 b) values_sep)
  ] initial-rows
  
  ;; Stocker les données initiales avec COPIE PROFONDE
  set initial-turtles-data []
  set initial-turtles-data-copy []
  
  foreach initial-rows [ row ->
    let prev-val     to-number-locale (item 3 row) values_sep
    let opin-val     to-number-locale (item 4 row) values_sep
    let infl-val     to-number-locale (item 5 row) values_sep
    let mplus-val    to-number-locale (item 6 row) values_sep
    let mminus-val   to-number-locale (item 7 row) values_sep
    let mplusw-val   to-number-locale (item 8 row) values_sep
    let mminusw-val  to-number-locale (item 9 row) values_sep
    let meta-val     item 10 row   ;; ← NOUVEAU (string)
    
    let agent-data (list
      prev-val
      opin-val
      infl-val
      mplus-val
      mminus-val
      mplusw-val
      mminusw-val
      meta-val
    )
    
    set initial-turtles-data lput agent-data initial-turtles-data
    set initial-turtles-data-copy lput (copy-list agent-data) initial-turtles-data-copy
  ]
end 


;; Nouvelle fonction pour copier une liste en profondeur
;; Alternative avec la syntaxe ?
;; Correction de la fonction copy-list

to-report copy-list [lst]
  let new-list []
  foreach lst [ un-element ->  ;; Renommé de "item" à "un-element"
    ifelse is-list? un-element [
      set new-list lput (copy-list un-element) new-list
    ] [
      set new-list lput un-element new-list
    ]
  ]
  report new-list
end 


;; NOUVELLE PROCÉDURE pour restaurer l'état initial
;; CORRECTION de restore-initial-state

to restore-initial-state
  clear-turtles
  clear-links
  
  if not is-list? initial-turtles-data-copy or empty? initial-turtles-data-copy [
    user-message "No initial state stored! Please import a file first."
    stop
  ]
  
  ;; Recharger les données depuis la copie
  set initial-turtles-data []
  foreach initial-turtles-data-copy [ agent-data ->
    set initial-turtles-data lput (copy-list agent-data) initial-turtles-data
  ]
  
  let n length initial-turtles-data
  if n > pop [ set n pop ]
  
  set meta-agents 0
  
  create-turtles n [
    let agent-data item who initial-turtles-data
    
    set prevalence    item 0 agent-data
    set opinion       item 1 agent-data
    set influence     item 2 agent-data
    set meme-plus     item 3 agent-data
    set meme-minus    item 4 agent-data
    set meme-plus-w   item 5 agent-data
    set meme-minus-w  item 6 agent-data
    set meta-type     item 7 agent-data   ;; ← NOUVEAU
    
    set opinion-previous opinion
    set influence-previous influence
    set tx-bonus 0
    set cascade-id 0
    set constellation-prev 0
    
    ;; safe bounds
    if prevalence < 0 [ set prevalence 0 ]
    if prevalence > 99 [ set prevalence 99 ]
    if opinion < -1 [ set opinion -1 ]
    if opinion > 1 [ set opinion 1 ]
    if influence < 0 [ set influence 0 ]
    if influence > 1 [ set influence 1 ]
    
    ;; Définir couleur et type
    ifelse opinion < 0 [
      set agent-type "Left side"
      set color red
    ] [
      ifelse opinion > 0 [
        set agent-type "Right side"
        set color blue
      ] [
        set agent-type "Center"
        set color white
      ]
    ]
    
    
    ;; Restaurer les méta structurels et dynamiques
    if meta-type = "structural" [
      set color yellow
      set meta-agents meta-agents + 1
    ]
    
    if meta-type = "dynamic" [
      set color yellow
    ]
    
    update-3d self
  ]
  
  update-networks
  apply-link-visibility
  recolor-links
  
  set repet_data true
  set import-mode "values"
  set tick-event event-init
  set inject-tick inject-base
  set iter 0
  reset-ticks
end 


;; CORRECTION de in_file_values

to in_file_values
  if setup? = 0 [
    user-message "Please click SETUP first before loading file!"
    stop
  ]
  carefully [
    set values_file_in user-file
    if values_file_in = false [ stop ]

    set list_values_data []
    file-open values_file_in

    if file-at-end? [
      user-message "Empty file"
      stop
    ]
    let header file-read-line

    ifelse (position ";" header != false)
      [ set values_sep ";" ]
      [ set values_sep "," ]

    while [not file-at-end?] [
      let line file-read-line
      if line != "" [
        let cols split-by line values_sep
        set list_values_data lput cols list_values_data
      ]
    ]
    file-close

    if empty? list_values_data [
      user-message "No data found in file"
      stop
    ]

    set import-mode "values"
    set repet_data true

    ;; *** CORRECTION ICI ***
    ;; On utilise le tick choisi par l’utilisateur
    set initial-tick-loaded choice_iter

    user-message (word "File uploaded (values CSV)! "
                       length list_values_data
                       " lines loaded. Using tick "
                       initial-tick-loaded
                       " as initial state.")
    
    ;; Charger et STOCKER l'état initial
    load-and-store-initial-state
    
    ;; Créer la population initiale
    restore-initial-state
    
  ] [
    user-message (word "Values file read error: " error-message)
    stop
  ]
  set file-imported? true
end 

to data
  ifelse import-mode = "values" [
    data-values
  ] [
    data-simple
  ]
end 

;; CORRECTION de data-simple

to data-simple
  clear-turtles
  clear-links
  
  ;; Utiliser les données stockées dans simple-initial-data
  if not is-list? simple-initial-data or empty? simple-initial-data [
    user-message "No simple data loaded! Please import a file first."
    stop
  ]
  
  let tick-to-load choice_iter
  
  ;; Filtrer les données pour le tick demandé
  let filtered-data filter [ row -> first row = tick-to-load ] simple-initial-data
  
  if empty? filtered-data [
    let available remove-duplicates map [row -> first row] simple-initial-data
    user-message (word "No data for tick " tick-to-load ". Available ticks: " available)
    stop
  ]
  
  let n min list pop length filtered-data
  let selected-data sublist filtered-data 0 n
  
  set meta-agents 0
  
  create-turtles n [
    let agent-data item who selected-data
    
    set prevalence item 1 agent-data
    set opinion    item 2 agent-data
    set influence  item 3 agent-data
    
    if influence = 1 [ set meta-agents meta-agents + influence ]
    
    set opinion-previous opinion
    set influence-previous influence
    set tx-bonus 0
    set cascade-id 0
    set constellation-prev 0
    
    ;; Initialiser les mèmes
    init-memes-from-state
    
    ;; Définir la couleur
    ifelse opinion < 0 [
      set color red
      set agent-type "Left side"
    ] [
      ifelse opinion > 0 [
        set color blue
        set agent-type "Right side"
      ] [
        set color white
        set agent-type "Center"
      ]
    ]
    
    if influence = 1 [ set color yellow ]
    
    update-3d self
  ]
  
  ;; Diagnostic
  output-print "=== RESTORE SIMPLE INITIAL STATE ==="
  output-print (word "Total agents: " count turtles)
  output-print (word "Current tick: " ticks)
  
  let left-agents turtles with [opinion < 0]
  let right-agents turtles with [opinion > 0]
  
  output-print (word "Left side (opinion < 0): " count left-agents " agents")
  output-print (word "Right side (opinion > 0): " count right-agents " agents")
  output-print (word "Influencers: " meta-agents " agents")
  
  ;; Afficher des exemples
  output-print "Examples of left agents (opinion < 0):"
  ifelse any? left-agents [
    let sample-size min (list 3 count left-agents)
    let samples sort [who] of n-of sample-size left-agents
    foreach samples [ id ->
      ask turtle id [
        output-print (word "  Agent " who ": opinion=" precision opinion 6 " color=" color)
      ]
    ]
  ] [
    output-print "  NO LEFT AGENTS FOUND!"
  ]
  
  output-print "Examples of right agents (opinion > 0):"
  ifelse any? right-agents [
    let sample-size min (list 3 count right-agents)
    let samples sort [who] of n-of sample-size right-agents
    foreach samples [ id ->
      ask turtle id [
        output-print (word "  Agent " who ": opinion=" precision opinion 6 " color=" color)
      ]
    ]
  ] [
    output-print "  NO RIGHT AGENTS FOUND!"
  ]
  
  output-print "================================"
  
  update-networks
  apply-link-visibility
  recolor-links
  
  set repet_data true
  set import-mode "simple"
  set tick-event event-init
  set inject-tick inject-base
  set iter 0
  reset-ticks
end 

to data-values
  ;; Cette procédure ne fait que restaurer l'état initial stocké
  restore-initial-state
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; UPDATE OPINIONS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-opinions
  ask turtles [
    set opinion-previous opinion
    let target one-of link-neighbors

    if target != nobody [
      let raw-dprev ([prevalence] of target) - prevalence
      if raw-dprev < 1 [ set raw-dprev 0 ]
      let dprev raw-dprev / max-prevalence

      if dprev > 0 [
        let dmem abs(abs(opinion) - abs([opinion] of target))

        let base-prob dprev * prevalence-weight
        let pol-penalty max list adoption-floor (1 - polarization-factor * dmem)
        let p-adopt base-prob * pol-penalty * [influence] of target * (1 + [tx-bonus] of target)

        let sgn-emitter sign ([opinion] of target)
        let gprob group-alignment-effective self sgn-emitter
        let w group-impact-weight
        let alpha group-impact-alpha
        set p-adopt p-adopt * ((1 - w) + (w * (gprob ^ alpha)))

        if p-adopt < 0 [ set p-adopt 0 ]
        if p-adopt > 1 [ set p-adopt 1 ]

        if random-float 1 < p-adopt [
          set old-opinion opinion
          set proposed-opinion [opinion] of target

          ifelse use-memes? [
            transmit-memes target
            recompute-from-memes
          ] [
            maybe-set-opinion proposed-opinion
          ]

          if opinion = old-opinion [ stop ]
          set total total + 1

          if opinion != old-opinion [
            if [cascade-id] of target != 0 [
              set cascade-id [cascade-id] of target
            ]
            if cascade-id = 0 [
              set last-cascade-id last-cascade-id + 1
              set cascade-id last-cascade-id
            ]

            set cascade-sizes lput (list ticks who [opinion] of target cascade-id) cascade-sizes

            if length cascade-sizes > 1000 [
              let start length cascade-sizes - 1000
              set cascade-sizes sublist cascade-sizes start length cascade-sizes
            ]
          ]

          let emitter-sign sign ([opinion] of target)
          let eligible? (reward-scope = "both") or
                        (reward-scope = "left-only"  and emitter-sign < 0) or
                        (reward-scope = "right-only" and emitter-sign >= 0)
          if eligible? [
            ask target [
              set tx-bonus min (list reward-cap (tx-bonus + reward-step))
            ]
          ]

          if reward-prev-delta > 0 [
            set prevalence min (list max-prevalence (prevalence + reward-prev-delta))
          ]

          set influence-previous influence
if vary-influence = true [
  if abs(old-opinion) > abs(opinion) [
    set influence min (list 1 (influence + rate-infl))
    if (influence-previous < 1 and influence = 1) [
      ;; L’agent devient méta dynamique
      set meta-type "dynamic"

      if meta-ok = true [
        if meta-links < meta-max [ set meta-links meta-links + 1 ]
        set meta-agents meta-agents + 1
      ]
      set color yellow
    ]
            ]
            if abs(old-opinion) < abs(opinion) [
              set influence max (list 0 (influence - rate-infl))
              if (influence < influence-previous and influence-previous = 1) [

  ;; Si c’est un méta dynamique → il perd son statut
  if meta-type = "dynamic" [
    set meta-type "none"
    if meta-ok = true [
      set meta-agents meta-agents - 1
      ifelse opinion >= 0 [ set color blue ] [ set color red ]
    ]
  ]

  ;; Si c’est un méta structurel → il reste méta
  if meta-type = "structural" [
    ;; on restaure son influence à 1
    set influence 1
    set color yellow
  ]
]
            ]
          ]

          if (sign old-opinion) != (sign opinion) [
            set change change + 1
          ]

          if change > 0 [
            set memes-per-change (((sum [meme-plus + meme-minus] of turtles) / change) / pop)
          ]
        ]
      ]
    ]

    if mode_prev = true [
      if prevalence > abs opinion * 100 [
        set prevalence prevalence - abs(opinion - opinion-previous) * influence * rate-mod
      ]
      if prevalence < abs opinion * 100 [
        set prevalence prevalence + abs(opinion - opinion-previous) * influence * rate-mod
      ]
      if prevalence < min-prevalence [ set prevalence min-prevalence ]
      if prevalence > max-prevalence [ set prevalence max-prevalence ]
    ]

    if random-float 1 < noise [
      let delta (random-float 0.4 - 0.2)
      maybe-set-opinion (opinion + delta)
    ]

    if use-memes? [ decay-memes ]
    update-3d self

    if (output = "Values") [ compute-statistics ]
  ]

  if reward-decay > 0 [
    ask turtles [ set tx-bonus max (list 0 (tx-bonus - reward-decay)) ]
  ]

  ifelse (total > 0)
    [ set inversion (100 * change / total) ]
    [ set inversion 0 ]

  if ticks mod 1000 = 0 [
    ask turtles [ set cascade-id 0 ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CONSTELLATIONS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-constellations
  compute-turnover
  compute-constellation-membership
  compute-constellation-stats
  compute-entropy
  compute-volatility
end 

to compute-constellation-membership
  set constellation-1-size 0
  set constellation-2-size 0
  set constellation-3-size 0
  set constellation-4-size 0
  set constellation-5-size 0

  let total-op-c1 0
  let total-op-c2 0
  let total-op-c3 0
  let total-op-c4 0
  let total-op-c5 0

  let total-prev-c1 0
  let total-prev-c2 0
  let total-prev-c3 0
  let total-prev-c4 0
  let total-prev-c5 0

  ask turtles [
    let const get-constellation self

    if const = 1 [
      set constellation-1-size constellation-1-size + 1
      set total-op-c1 total-op-c1 + opinion
      set total-prev-c1 total-prev-c1 + prevalence
    ]
    if const = 2 [
      set constellation-2-size constellation-2-size + 1
      set total-op-c2 total-op-c2 + opinion
      set total-prev-c2 total-prev-c2 + prevalence
    ]
    if const = 3 [
      set constellation-3-size constellation-3-size + 1
      set total-op-c3 total-op-c3 + opinion
      set total-prev-c3 total-prev-c3 + prevalence
    ]
    if const = 4 [
      set constellation-4-size constellation-4-size + 1
      set total-op-c4 total-op-c4 + opinion
      set total-prev-c4 total-prev-c4 + prevalence
    ]
    if const = 5 [
      set constellation-5-size constellation-5-size + 1
      set total-op-c5 total-op-c5 + opinion
      set total-prev-c5 total-prev-c5 + prevalence
    ]

    set constellation-prev const
  ]

  set constellation-1-opinion-avg ifelse-value (constellation-1-size > 0) [ total-op-c1 / constellation-1-size ] [ 0 ]
  set constellation-2-opinion-avg ifelse-value (constellation-2-size > 0) [ total-op-c2 / constellation-2-size ] [ 0 ]
  set constellation-3-opinion-avg ifelse-value (constellation-3-size > 0) [ total-op-c3 / constellation-3-size ] [ 0 ]
  set constellation-4-opinion-avg ifelse-value (constellation-4-size > 0) [ total-op-c4 / constellation-4-size ] [ 0 ]
  set constellation-5-opinion-avg ifelse-value (constellation-5-size > 0) [ total-op-c5 / constellation-5-size ] [ 0 ]

  set constellation-1-prev-avg ifelse-value (constellation-1-size > 0) [ total-prev-c1 / constellation-1-size ] [ 0 ]
  set constellation-2-prev-avg ifelse-value (constellation-2-size > 0) [ total-prev-c2 / constellation-2-size ] [ 0 ]
  set constellation-3-prev-avg ifelse-value (constellation-3-size > 0) [ total-prev-c3 / constellation-3-size ] [ 0 ]
  set constellation-4-prev-avg ifelse-value (constellation-4-size > 0) [ total-prev-c4 / constellation-4-size ] [ 0 ]
  set constellation-5-prev-avg ifelse-value (constellation-5-size > 0) [ total-prev-c5 / constellation-5-size ] [ 0 ]
end 

to compute-constellation-stats
  let var-op-c1 0
  let var-op-c2 0
  let var-op-c3 0
  let var-op-c4 0
  let var-op-c5 0

  ask turtles [
    let const get-constellation self
    if const = 1 [
      set var-op-c1 var-op-c1 + ((opinion - constellation-1-opinion-avg) ^ 2)
    ]
    if const = 2 [
      set var-op-c2 var-op-c2 + ((opinion - constellation-2-opinion-avg) ^ 2)
    ]
    if const = 3 [
      set var-op-c3 var-op-c3 + ((opinion - constellation-3-opinion-avg) ^ 2)
    ]
    if const = 4 [
      set var-op-c4 var-op-c4 + ((opinion - constellation-4-opinion-avg) ^ 2)
    ]
    if const = 5 [
      set var-op-c5 var-op-c5 + ((opinion - constellation-5-opinion-avg) ^ 2)
    ]
  ]

  set constellation-1-polarization ifelse-value (constellation-1-size > 1) [ sqrt (var-op-c1 / constellation-1-size) ] [ 0 ]
  set constellation-2-polarization ifelse-value (constellation-2-size > 1) [ sqrt (var-op-c2 / constellation-2-size) ] [ 0 ]
  set constellation-3-polarization ifelse-value (constellation-3-size > 1) [ sqrt (var-op-c3 / constellation-3-size) ] [ 0 ]
  set constellation-4-polarization ifelse-value (constellation-4-size > 1) [ sqrt (var-op-c4 / constellation-4-size) ] [ 0 ]
  set constellation-5-polarization ifelse-value (constellation-5-size > 1) [ sqrt (var-op-c5 / constellation-5-size) ] [ 0 ]
end 

to-report get-constellation [agent]
  let op [opinion] of agent
  let prev [prevalence] of agent

  if op < (- c-opinion-extreme) and prev >= c-prevalence-high [
    report 1
  ]
  if op < (- c-opinion-moderate) and op >= (- c-opinion-extreme) [
    report 2
  ]
  if op >= (- c-opinion-moderate) and op <= c-opinion-moderate [
    report 3
  ]
  if op > c-opinion-moderate and op <= c-opinion-extreme [
    report 4
  ]
  if op > c-opinion-extreme and prev >= c-prevalence-high [
    report 5
  ]

  if op < 0 [ report 2 ]
  if op > 0 [ report 4 ]
  report 3
end 

to compute-turnover
  let changes 0
  let changes-c1 0
  let changes-c2 0
  let changes-c3 0
  let changes-c4 0
  let changes-c5 0

  let prev-size-c1 0
  let prev-size-c2 0
  let prev-size-c3 0
  let prev-size-c4 0
  let prev-size-c5 0

  ask turtles [
    let current-const get-constellation self
    let prev-const constellation-prev

    if prev-const > 0 [
      if prev-const != current-const [
        set changes changes + 1
        if prev-const = 1 [ set changes-c1 changes-c1 + 1 ]
        if prev-const = 2 [ set changes-c2 changes-c2 + 1 ]
        if prev-const = 3 [ set changes-c3 changes-c3 + 1 ]
        if prev-const = 4 [ set changes-c4 changes-c4 + 1 ]
        if prev-const = 5 [ set changes-c5 changes-c5 + 1 ]
      ]

      if prev-const = 1 [ set prev-size-c1 prev-size-c1 + 1 ]
      if prev-const = 2 [ set prev-size-c2 prev-size-c2 + 1 ]
      if prev-const = 3 [ set prev-size-c3 prev-size-c3 + 1 ]
      if prev-const = 4 [ set prev-size-c4 prev-size-c4 + 1 ]
      if prev-const = 5 [ set prev-size-c5 prev-size-c5 + 1 ]
    ]
  ]

  set turnover-global ifelse-value (pop > 0) [ 100 * changes / pop ] [ 0 ]
  set turnover-c1 ifelse-value (prev-size-c1 > 0) [ 100 * changes-c1 / prev-size-c1 ] [ 0 ]
  set turnover-c2 ifelse-value (prev-size-c2 > 0) [ 100 * changes-c2 / prev-size-c2 ] [ 0 ]
  set turnover-c3 ifelse-value (prev-size-c3 > 0) [ 100 * changes-c3 / prev-size-c3 ] [ 0 ]
  set turnover-c4 ifelse-value (prev-size-c4 > 0) [ 100 * changes-c4 / prev-size-c4 ] [ 0 ]
  set turnover-c5 ifelse-value (prev-size-c5 > 0) [ 100 * changes-c5 / prev-size-c5 ] [ 0 ]
end 

to compute-entropy
  let bins (list -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1 
                0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0)
  let counts []
  let i 0

  while [i < 20] [
    let lower item i bins
    let upper item (i + 1) bins
    let in-bin count turtles with [opinion >= lower and opinion < upper]
    set counts lput in-bin counts
    set i i + 1
  ]

  let last-bin item 20 bins
  let in-last count turtles with [opinion >= last-bin]
  set counts replace-item 19 counts (in-last)

  let total-pop pop
  let entropy 0

  foreach counts [ c ->
    if c > 0 [
      let p c / total-pop
      set entropy entropy - (p * log p 2)
    ]
  ]

  set opinion-entropy entropy
end 

to compute-volatility
  let center-opinion ifelse-value (constellation-3-size > 0) 
    [ constellation-3-opinion-avg ] 
    [ 0 ]

  if ticks > 1 [
    let delta abs (center-opinion - last-center-opinion)
    set center-volatility 0.3 * delta + 0.7 * center-volatility
  ]

  set last-center-opinion center-opinion
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FRACTAL DIMENSIONS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to capture-network-snapshot
  if ticks mod 50 = 0 [
    let snapshot get-current-network
    set network-snapshots lput (list ticks snapshot) network-snapshots
    if length network-snapshots > 20 [
      set network-snapshots but-first network-snapshots
    ]
  ]
end 

to-report get-current-network
  let edges []
  ask links [
    set edges lput (list [who] of end1 [who] of end2) edges
  ]
  report edges
end 

to compute-fractal-dimensions
  set topological-dimension compute-topological-dimension
  set dynamic-dimension compute-dynamic-dimension

  if topological-dimension > 0 [
    set criticality-gap abs(dynamic-dimension - topological-dimension) / topological-dimension
  ]

  if ticks mod 500 = 0 [
    output-print (word "Ticks: " ticks 
      " | D_top: " topological-dimension
      " | D_dyn: " dynamic-dimension
      " | Gap: " criticality-gap)
  ]
end 

to-report compute-topological-dimension
  let edges get-current-network
  if length edges < 10 [ report 0 ]

  let results []

  foreach box-sizes [ r ->
    let box-radius max list 1 (round (r * pop / 10))
    let unvisited sort [who] of turtles
    let n-boxes 0

    while [not empty? unvisited] [
      let seed first unvisited
      let in-box [who] of bfs-reachable (turtle seed) box-radius
      set unvisited filter [ [x] -> not member? x in-box ] unvisited
      set n-boxes n-boxes + 1
    ]

    set results lput (list (ln (1 / r)) (ln n-boxes)) results
  ]

  report regression-slope results
end 

to-report bfs-reachable [start-node max-dist]
  if start-node = nobody [ report no-turtles ]

  let visited (turtle-set start-node)
  let frontier (turtle-set start-node)
  let dist 0

  while [dist < max-dist and any? frontier] [
    let new-frontier (turtle-set)
    ask frontier [
      let neighbors-set link-neighbors
      set new-frontier (turtle-set new-frontier neighbors-set)
    ]
    set visited (turtle-set visited new-frontier)
    set frontier new-frontier
    set dist dist + 1
  ]

  report visited
end 

to-report compute-dynamic-dimension
  if length cascade-sizes < 100 [ report 0 ]

  let sizes []
  let current-cascade 0
  let current-size 0

  let sorted-cascades sort-by [ [a b] -> item 3 a < item 3 b ] cascade-sizes

  foreach sorted-cascades [ evt ->
    let cid item 3 evt
    ifelse cid != current-cascade [
      if current-size > 0 [ set sizes lput current-size sizes ]
      set current-cascade cid
      set current-size 1
    ] [
      set current-size current-size + 1
    ]
  ]
  if current-size > 0 [ set sizes lput current-size sizes ]

  set sizes filter [x -> x > 1] sizes
  if length sizes < 20 [ report 0 ]

  let unique-sizes remove-duplicates sort sizes
  let ccdf []

  foreach unique-sizes [ s ->
    let count-greater length filter [x -> x >= s] sizes
    if count-greater > 0 [
      set ccdf lput (list (ln s) (ln count-greater)) ccdf
    ]
  ]

  if length ccdf < 5 [ report 0 ]

  let slope regression-slope ccdf
  if slope < -10 or slope > 10 [ report 0 ]
  report abs slope
end 

to-report regression-slope [points]
  let n length points
  if n < 2 [ report 0 ]

  let sum-x 0
  let sum-y 0
  let sum-xy 0
  let sum-x2 0

  foreach points [ p ->
    let x item 0 p
    let y item 1 p
    set sum-x sum-x + x
    set sum-y sum-y + y
    set sum-xy sum-xy + x * y
    set sum-x2 sum-x2 + x * x
  ]

  let slope (n * sum-xy - sum-x * sum-y) / (n * sum-x2 - sum-x * sum-x)
  report slope
end 

to-report self-organization-evidence
  if length criticality-history < 10 [ report false ]

  let first-gap item 2 (item 0 criticality-history)
  let last-gap item 2 (item (length criticality-history - 1) criticality-history)

  report last-gap < first-gap * 0.7
end 

to-report system-status
  let f fractale
  let d_top topological-dimension
  let d_dyn dynamic-dimension
  let gap criticality-gap

  if d_top = 0 or d_dyn = 0 [
    report "Initializing..."
  ]

  if gap < 0.2 [
    if abs(f - d_dyn) < 0.3 [
      if abs(f - d_top) < 0.3 [
        report "🌟🌟 PERFECT CRITICALITY: structure, dynamics AND process aligned"
      ]
      report "⭐ DYNAMIC CRITICALITY: good process↔dynamics alignment"
    ]
    if abs(f - d_top) < 0.3 [
      report "⭐ STRUCTURAL CRITICALITY: good process↔network alignment"
    ]
    report "⚡ CRITICALITY: structure and dynamics aligned, autonomous process"
  ]

  if gap < 0.5 [
    if f > 1.5 [
      report "🌀 EXPLORATION: complex process in moderately adapted structure"
    ]
    if f < 1 [
      report "🌀 SIMPLICITY: linear process, structure adapting"
    ]
    report "🌀 INTERMEDIATE REGIME: system exploring possibility space"
  ]

  if d_dyn > d_top * 1.5 [
    report "⚠️ DECOUPLING: dynamics richer than structure (check measurements)"
  ]
  if d_dyn < d_top * 0.5 [
    report "⚠️ UNDERUTILIZATION: rich structure but little influence"
  ]
  report "⚠️ OUTSIDE CRITICALITY: structure and dynamics desynchronized"
end 

to-report system-status-code
  let gap criticality-gap
  if gap < 0.2 [ report 3 ]
  if gap < 0.5 [ report 2 ]
  report 1
end 

to-report system-regime
  let f fractale
  let d_top topological-dimension
  let d_dyn dynamic-dimension
  let gap criticality-gap
  let turn turnover-global
  let entr opinion-entropy
  let volt center-volatility

  if d_top = 0 or d_dyn = 0 or ticks < 100 [
    report "⚪ INITIALIZATION: System stabilizing, waiting for sufficient data"
  ]

  let f-high-threshold 1.6
  let f-low-threshold 1.3
  let gap-low-threshold 0.2
  let gap-high-threshold 0.5
  let turn-low-threshold 3.0
  let turn-mod-high-threshold 8.0
  let turn-high-threshold 15.0
  let entr-low-threshold 2.5
  let entr-high-threshold 3.5
  let volt-low-threshold 0.2
  let volt-mod-high-threshold 0.4
  let volt-high-threshold 0.6

  let f-qual ifelse-value (f >= f-high-threshold) 
    [ "High" ] 
    [ ifelse-value (f <= f-low-threshold) 
      [ "Low" ] 
      [ "Moderate" ] ]

  let gap-qual ifelse-value (gap <= gap-low-threshold) 
    [ "Low" ] 
    [ ifelse-value (gap >= gap-high-threshold) 
      [ "High" ] 
      [ "Moderate" ] ]

  let turn-qual ifelse-value (turn >= turn-high-threshold) 
    [ "Very High" ] 
    [ ifelse-value (turn >= turn-mod-high-threshold) 
      [ "High" ] 
      [ ifelse-value (turn >= turn-low-threshold) 
        [ "Moderate" ] 
        [ "Low" ] ] ]

  let entr-qual ifelse-value (entr >= entr-high-threshold) 
    [ "High" ] 
    [ ifelse-value (entr <= entr-low-threshold) 
      [ "Low" ] 
      [ "Moderate" ] ]

  let volt-qual ifelse-value (volt >= volt-high-threshold) 
    [ "Very High" ] 
    [ ifelse-value (volt >= volt-mod-high-threshold) 
      [ "High" ] 
      [ ifelse-value (volt >= volt-low-threshold) 
        [ "Moderate" ] 
        [ "Low" ] ] ]

  if (f-qual = "High") and (gap-qual = "Low") and 
     (turn-qual = "Moderate") and (entr-qual = "High") and 
     (volt-qual = "Moderate") [
    report (word "🌟 EMERGENT CRITICAL: " 
      "System at the edge of chaos, rich and diverse, ideal for social innovation "
      "[Fractal: " f-qual ", Criticality: " gap-qual 
      ", Turnover: " turn-qual ", Entropy: " entr-qual ", Volatility: " volt-qual "]")
  ]

  if (f-qual = "High") and (gap-qual = "Low") and 
     (turn-qual = "Low") and (entr-qual = "Moderate") and 
     (volt-qual = "Low") [
    report (word "🏛️ MATURE STRUCTURED: "
      "Crystallized complexity, well-organized but inflexible society "
      "[Fractal: " f-qual ", Criticality: " gap-qual 
      ", Turnover: " turn-qual ", Entropy: " entr-qual ", Volatility: " volt-qual "]")
  ]

  if (f-qual = "High") and (gap-qual = "High") and 
     (turn-qual = "High" or turn-qual = "Very High") and 
     (entr-qual = "High") and (volt-qual = "High" or volt-qual = "Very High") [
    report (word "🌪️ TURBULENT: "
      "Rich but disorganized, risk of collapse or transition "
      "[Fractal: " f-qual ", Criticality: " gap-qual 
      ", Turnover: " turn-qual ", Entropy: " entr-qual ", Volatility: " volt-qual "]")
  ]

  if (f-qual = "Low") and (gap-qual = "Low") and 
     (turn-qual = "Low") and (entr-qual = "Low") and 
     (volt-qual = "Low") [
    report (word "🧊 GLACIAL: "
      "Frozen system, total consensus, absence of dynamics "
      "[Fractal: " f-qual ", Criticality: " gap-qual 
      ", Turnover: " turn-qual ", Entropy: " entr-qual ", Volatility: " volt-qual "]")
  ]

  if (f-qual = "Moderate") and (gap-qual = "Moderate") and 
     (turn-qual = "High") and (entr-qual = "Moderate") and 
     (volt-qual = "High" or volt-qual = "Very High") [
    report (word "🔥 PRE-ERUPTIVE: "
      "Highly volatile center, warning signs of tipping "
      "[Fractal: " f-qual ", Criticality: " gap-qual 
      ", Turnover: " turn-qual ", Entropy: " entr-qual ", Volatility: " volt-qual "]")
  ]

  if (turn-qual = "Very High") and (volt-qual = "Very High") [
    report (word "💥 EXPLOSIVE: "
      "Crisis underway, everything changing rapidly "
      "[Fractal: " f-qual ", Criticality: " gap-qual 
      ", Turnover: " turn-qual ", Entropy: " entr-qual ", Volatility: " volt-qual "]")
  ]

  report (word "🔄 MIXED REGIME: System in transition or intermediate state "
    "[Fractal: " f-qual ", Criticality: " gap-qual 
    ", Turnover: " turn-qual ", Entropy: " entr-qual ", Volatility: " volt-qual "]")
end 

to-report system-regime-code
  let f fractale
  let d_top topological-dimension
  let d_dyn dynamic-dimension
  let gap criticality-gap
  let turn turnover-global
  let entr opinion-entropy
  let volt center-volatility

  if d_top = 0 or d_dyn = 0 or ticks < 100 [ report 0 ]

  let f-high 1.6
  let f-low 1.3
  let gap-low 0.2
  let gap-high 0.5
  let turn-mod 3.0
  let turn-high 8.0
  let turn-vhigh 15.0
  let entr-low 2.5
  let entr-high 3.5
  let volt-mod 0.2
  let volt-high 0.4
  let volt-vhigh 0.6

  if (f >= f-high) and (gap <= gap-low) and 
     (turn >= turn-mod and turn < turn-high) and 
     (entr >= entr-high) and (volt >= volt-mod and volt < volt-high) [
    report 1
  ]

  if (f >= f-high) and (gap <= gap-low) and 
     (turn < turn-mod) and (entr >= entr-low and entr < entr-high) and 
     (volt < volt-mod) [
    report 2
  ]

  if (f >= f-high) and (gap >= gap-high) and 
     (turn >= turn-high) and (entr >= entr-high) and 
     (volt >= volt-high) [
    report 3
  ]

  if (f <= f-low) and (gap <= gap-low) and 
     (turn < turn-mod) and (entr <= entr-low) and 
     (volt < volt-mod) [
    report 4
  ]

  if (f > f-low and f < f-high) and (gap > gap-low and gap < gap-high) and 
     (turn >= turn-high) and (entr > entr-low and entr < entr-high) and 
     (volt >= volt-high) [
    report 5
  ]

  if (turn >= turn-vhigh) and (volt >= volt-vhigh) [
    report 6
  ]

  report 0
end 

to calibrate-regime-thresholds
  output-print "=================================================="
  output-print "Current regime thresholds:"
  output-print (word "Fractal High: " 1.6 " | Low: " 1.3)
  output-print (word "Criticality Gap Low: " 0.2 " | High: " 0.5)
  output-print (word "Turnover Low: " 3.0 "% | Mod-High: " 8.0 "% | High: " 15.0 "%")
  output-print (word "Entropy Low: " 2.5 " | High: " 3.5)
  output-print (word "Volatility Low: " 0.2 " | Mod-High: " 0.4 " | High: " 0.6)
  output-print "=================================================="
  output-print "To modify thresholds, edit the values in system-regime procedure"
end 

to diagnose-system
  output-print "=================================================="
  output-print (word "SYSTEM DIAGNOSIS at tick " ticks)
  output-print "=================================================="
  output-print system-regime

  output-print ""
  output-print "--- Detailed Values ---"
  output-print (word "Fractal: " fractale)
  output-print (word "Topological Dim: " topological-dimension)
  output-print (word "Dynamic Dim: " dynamic-dimension)
  output-print (word "Criticality Gap: " criticality-gap)
  output-print (word "Global Turnover: " turnover-global "%")
  output-print (word "Opinion Entropy: " opinion-entropy)
  output-print (word "Center Volatility: " center-volatility)
  output-print (word "Lyapunov Exponent: " lyapunov-exponent)

  output-print ""
  output-print "--- Constellation Sizes ---"
  output-print (word "C1 (Left Radicals): " constellation-1-size)
  output-print (word "C2 (Left Moderates): " constellation-2-size)
  output-print (word "C3 (Center): " constellation-3-size)
  output-print (word "C4 (Right Moderates): " constellation-4-size)
  output-print (word "C5 (Right Radicals): " constellation-5-size)

  output-print "=================================================="
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; LYAPUNOV PROCEDURES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to compute-lyapunov-exponent
  let n length divergence-history
  if n < 10 [ stop ]

  let points []
  foreach divergence-history [ d ->
    set points lput (list (ln (item 0 d)) (ln (item 1 d))) points
  ]

  set lyapunov-exponent regression-slope points
end 

to initialize-perturbation
  set reference-trajectory []
  set perturbed-trajectory []

  let ref-state []
  ask turtles [
    set ref-state lput (list who opinion prevalence influence) ref-state
  ]
  set reference-trajectory lput (list ticks ref-state) reference-trajectory

  ask turtles [
    set opinion opinion + random-float 2e-6 - 1e-6
    set opinion max list -1 min list 1 opinion
  ]

  let pert-state []
  ask turtles [
    set pert-state lput (list who opinion prevalence influence) pert-state
  ]
  set perturbed-trajectory lput (list ticks pert-state) perturbed-trajectory
end 

to update-perturbation
  if length reference-trajectory = 0 [ stop ]

  let last-ref last reference-trajectory
  let last-pert last perturbed-trajectory

  let divergence 0
  let n 0

  foreach (item 1 last-ref) [ ref-state ->
    let who-ref item 0 ref-state
    let match filter [p -> item 0 p = who-ref] (item 1 last-pert)
    if not empty? match [
      let pert-state first match
      let d-opinion (item 1 ref-state) - (item 1 pert-state)
      let d-prevalence (item 2 ref-state) - (item 2 pert-state)
      let d-influence (item 3 ref-state) - (item 3 pert-state)
      set divergence divergence + (d-opinion ^ 2 + d-prevalence ^ 2 + d-influence ^ 2)
      set n n + 1
    ]
  ]

  if n > 0 [
    set divergence sqrt (divergence / n)
    if divergence = 0 [ set divergence 0.0000001 ]
    set divergence-history lput (list ticks divergence) divergence-history

    if ticks mod 10 = 0 [
      rescale-perturbation
    ]
  ]

  let new-ref []
  let new-pert []
  ask turtles [
    set new-ref lput (list who opinion prevalence influence) new-ref
  ]

  ask turtles [
    set new-pert lput (list who opinion prevalence influence) new-pert
  ]

  set reference-trajectory lput (list ticks new-ref) reference-trajectory
  set perturbed-trajectory lput (list ticks new-pert) perturbed-trajectory

  if length reference-trajectory > 100 [
    set reference-trajectory but-first reference-trajectory
    set perturbed-trajectory but-first perturbed-trajectory
  ]
end 

to rescale-perturbation
  if length reference-trajectory = 0 [ stop ]

  let last-ref last reference-trajectory
  ask turtles [
    let my-ref filter [p -> item 0 p = who] (item 1 last-ref)
    if not empty? my-ref [
      let ref-state first my-ref
      let d-opinion opinion - (item 1 ref-state)
      let d-prevalence prevalence - (item 2 ref-state)
      let d-influence influence - (item 3 ref-state)

      let scale 0.01
      set opinion (item 1 ref-state) + d-opinion * scale
      set prevalence (item 2 ref-state) + d-prevalence * scale
      set influence (item 3 ref-state) + d-influence * scale

      set opinion max list -1 min list 1 opinion
      set prevalence max list 0 min list 99 prevalence
      set influence max list 0 min list 1 influence
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; VALUES OUTPUT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to compute-statistics
  if output = "Values" [
    output-print join-cols (list
      fmt try
      fmt ticks
      fmt who
      fmt prevalence
      fmt opinion
      fmt influence
      fmt meme-plus
      fmt meme-minus
      fmt meme-plus-w
      fmt meme-minus-w
    )
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COLORING
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to colorer
  ask turtles [
    ifelse meta? [ set color yellow set influence 1] [
      ifelse opinion >= 0 [ set color blue ] [ set color red ]
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NETWORK
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-networks
  let doomed links with [
    abs([opinion] of end1 - [opinion] of end2) > (link-removal-threshold / 100)
  ]
  let doomedProb doomed with [ random-float 1 < prob ]
  let n-remove min (list linksdown count doomedProb)
  if n-remove > 0 [
    ask n-of n-remove doomedProb [ die ]
    set links-dead links-dead + n-remove
  ]

  let j linksup
  while [j > 0] [
    let t one-of turtles
    if t = nobody [ stop ]
    ask t [
      let myop opinion
      let candidates other turtles with [ not link-neighbor? myself ]
      let pool-homo candidates with [ abs(opinion - myop) < (link-formation-threshold / 100) ]
      let pool-bridge candidates with [ (sign opinion) != (sign myop) ]

      let friend nobody
      if any? pool-bridge and (random-float 1 < bridge-prob) [
        set friend max-one-of pool-bridge [ abs(opinion - myop) ]
      ]
      if (friend = nobody) and any? pool-homo [
        set friend min-one-of pool-homo [ abs(opinion - myop) ]
      ]

      if friend != nobody and (random-float 1 < prob) [
        create-link-with friend
        set links-create links-create + 1
        let same-sign? (sign opinion) = (sign [opinion] of friend)
        ask link-with friend [
          set color (ifelse-value same-sign? [ green ] [ gray ])
          set thickness linktick
          if show-links [ show-link ]
        ]
      ]
    ]
    set j j - 1
  ]
end 

to meta
  if not network [ stop ]

  ask turtles with [meta-type = "structural"] [

    ;; déterminer le mode actuel selon la probabilité
    let mode meta-mode-auto

    ;; choisir si on cible un méta ou un non-méta
    let choose-meta?
      ifelse-value (mode = "non-meta")
        [ false ]   ;; déterministe : méta → non-méta
        [
          ifelse-value (mode = "meta")
            [ true ] ;; déterministe : méta → méta
            [ random-float 1 < meta-link-prob ] ;; probabiliste : mixte
        ]

    ;; construire le pool selon le choix
    let pool other turtles with [
      (ifelse-value choose-meta?
        [ color = yellow ]      ;; méta → méta
        [ color != yellow ]     ;; méta → non-méta
      ) and
      not link-neighbor? myself and
      (count link-neighbors) < meta-links
    ]

    ;; créer le lien si possible
    if any? pool [
      let friend one-of pool
      create-link-with friend

      let same-sign? (sign opinion) = (sign [opinion] of friend)
      ask link-with friend [
        set color (ifelse-value same-sign? [ green ] [ gray ])
        set thickness linktick
        if show-links [ show-link ]
      ]
    ]
  ]
end 

to-report meta-mode-auto
  if meta-link-prob = 0 [
    report "non-meta"
  ]
  if meta-link-prob = 1 [
    report "meta"
  ]
  report "mixed"
end 

to apply-link-visibility
  ifelse show-links [ ask links [ show-link ] ] [ ask links [ hide-link ] ]
end 

to recolor-links
  ask links [
    let s1 sign [opinion] of end1
    let s2 sign [opinion] of end2
    ifelse s1 = s2 [ set color green ] [ set color gray ]
    set thickness linktick
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; EVENT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to event
  ask turtles [
    let event-prob random-float 1
    if event-prob <= event-prob-max [
      ifelse meme_set = true [
        if (to_left = false) [
          if agent-type = "Right side" [
            if opinion < 0 [ maybe-set-opinion (opinion + event_size) ]
          ]
        ]
        if (to_left = true) [
          if agent-type = "Left side" [
            if opinion > 0 [ maybe-set-opinion (opinion - event_size) ]
          ]
        ]
      ] [
        if (to_left = false) [
          if (opinion < high_meme and opinion > low_meme and prevalence < high-prev and prevalence > low-prev) [
            maybe-set-opinion (opinion + event_size)
            if (prev_change != 0) [ set prevalence min (list max-prevalence (prevalence + prev_change)) ]
          ]
        ]
        if (to_left = true) [
          if (opinion > low_meme and opinion < high_meme and prevalence > low-prev and prevalence < high-prev) [
            maybe-set-opinion (opinion - event_size)
            if (prev_change != 0) [ set prevalence min (list max-prevalence (prevalence + prev_change)) ]
          ]
        ]
      ]
      if use-memes? and event-meme-change? [ init-memes-from-state ]
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MISCELLANEOUS UTILITIES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to set-background-black
  ask patches [ set pcolor black ]
end 

to update-3d [agt]
  ask agt [
    set x3d opinion * 16
    set y3d prevalence / 6
    set z3d influence * 16
    setxyz x3d y3d z3d
  ]
end 

to-report safe-median [agentset varname]
  if not any? agentset [ report 0 ]
  report median [ runresult varname ] of agentset
end 

to-report sign [x]
  ifelse x > 0 [ report 1 ] [ ifelse x < 0 [ report -1 ] [ report 0 ] ]
end 

to-report meme-saturation-pct
  if not use-memes? [ report 0 ]
  if not any? turtles [ report 0 ]
  let total-memes sum [meme-plus + meme-minus] of turtles
  let capacity meme-max * count turtles
  if capacity <= 0 [ report 0 ]
  report 100 * total-memes / capacity
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GROUP IMPACT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report group-alignment-all [agt sign-ref]
  let nbrs [link-neighbors] of agt
  if not any? nbrs [ report 0.5 ]
  let same count nbrs with [ (sign opinion) = sign-ref ]
  report same / count nbrs
end 

to-report group-alignment-k [agt sign-ref k]
  let nbrs [link-neighbors] of agt
  let deg count nbrs
  if deg = 0 [ report 0.5 ]
  let kk max list 1 min list deg floor k
  let agop [opinion] of agt
  let pool min-n-of kk nbrs [ abs(opinion - agop) ]
  if not any? pool [ report 0.5 ]
  let same count pool with [ (sign opinion) = sign-ref ]
  report same / count pool
end 

to-report group-alignment-effective [agt sign-ref]
  ifelse (group-impact-mode = "k-nearest")
    [ report group-alignment-k agt sign-ref group-k ]
    [ report group-alignment-all agt sign-ref ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MEMES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report initial-prevalence-to-memes [prev]
  report (prev / 99) * meme-max
end 

to init-memes-from-state
  let totq initial-prevalence-to-memes prevalence

  ifelse opinion >= 0 [
    set meme-plus  totq * (0.5 + 0.5 * abs opinion)
    set meme-minus totq - meme-plus
  ] [
    set meme-minus totq * (0.5 + 0.5 * abs opinion)
    set meme-plus  totq - meme-minus
  ]

  set meme-plus-w  meme-plus  * meme-weight-mean
  set meme-minus-w meme-minus * meme-weight-mean

  if meme-plus < 0 [ set meme-plus 0 ]
  if meme-minus < 0 [ set meme-minus 0 ]
  if meme-plus-w < 0 [ set meme-plus-w 0 ]
  if meme-minus-w < 0 [ set meme-minus-w 0 ]
end 

to-report draw-meme-weight
  let w meme-weight-mean
  if meme-weight-sd > 0 [
    set w (meme-weight-mean + (random-float (2 * meme-weight-sd) - meme-weight-sd))
  ]
  if w < meme-weight-min [ set w meme-weight-min ]
  if w > meme-weight-max [ set w meme-weight-max ]
  report w
end 

to recompute-from-memes
  let totw meme-plus-w + meme-minus-w
  if totw < 1e-6 [ set totw 1e-6 ]
  set proposed-opinion ((meme-plus-w - meme-minus-w) / totw)
  maybe-set-opinion proposed-opinion

  let totq meme-plus + meme-minus
  let scaled (totq / meme-max) * 99
  if scaled < 0 [ set scaled 0 ]
  if scaled > 99 [ set scaled 99 ]
  set prevalence scaled
end 

to decay-memes
  if meme-decay <= 0 [ stop ]
  let f (1 - meme-decay)
  set meme-plus    max list 0 (meme-plus    * f)
  set meme-minus   max list 0 (meme-minus   * f)
  set meme-plus-w  max list 0 (meme-plus-w  * f)
  set meme-minus-w max list 0 (meme-minus-w * f)
end 

to transmit-memes [emitter]
  let sgn sign ([opinion] of emitter)
  let w draw-meme-weight
  let leak (meme-anti-leak * meme-gain)

  ifelse sgn >= 0 [
    set meme-plus   meme-plus + meme-gain
    set meme-plus-w meme-plus-w + (w * meme-gain)

    set meme-minus   max list 0 (meme-minus - leak)
    set meme-minus-w max list 0 (meme-minus-w - (w * leak))
  ] [
    set meme-minus   meme-minus + meme-gain
    set meme-minus-w meme-minus-w + (w * meme-gain)

    set meme-plus   max list 0 (meme-plus - leak)
    set meme-plus-w max list 0 (meme-plus-w - (w * leak))
  ]

  let totq meme-plus + meme-minus
  if totq > meme-max [
    let factor meme-max / totq
    set meme-plus    meme-plus    * factor
    set meme-minus   meme-minus   * factor
    set meme-plus-w  meme-plus-w  * factor
    set meme-minus-w meme-minus-w * factor
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INJECTION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to inject-memes
  let base-pool turtles with [
    opinion >= inject-low_meme and opinion <= inject-high_meme and
    prevalence >= inject-low-prev and prevalence <= inject-high-prev
  ]

  let pool base-pool
  if inject-metas-only [
    set pool base-pool with [ color = yellow ]
  ]

  ask pool [
    if random-float 1 <= inject-prob-max [
      let w inject-weight
      if w < meme-weight-min [ set w meme-weight-min ]
      if w > meme-weight-max [ set w meme-weight-max ]

      if inject-amount < 0 [ stop ]

      if inject-sign = "plus" [
        set meme-plus   meme-plus + inject-amount
        set meme-plus-w meme-plus-w + (w * inject-amount)
      ]
      if inject-sign = "minus" [
        set meme-minus   meme-minus + inject-amount
        set meme-minus-w meme-minus-w + (w * inject-amount)
      ]

      let totq meme-plus + meme-minus
      if totq > meme-max [
        let factor meme-max / totq
        set meme-plus    meme-plus    * factor
        set meme-minus   meme-minus   * factor
        set meme-plus-w  meme-plus-w  * factor
        set meme-minus-w meme-minus-w * factor
      ]

      if use-memes? [ recompute-from-memes ]
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Additional reporters
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to-report mean-polarity-index
  let total-plus  sum [meme-plus] of turtles
  let total-minus sum [meme-minus] of turtles
  ifelse (total-plus + total-minus > 0)
    [ report (total-plus - total-minus) / (total-plus + total-minus) ]
    [ report 0 ]
end 

to-report ideologization-meme-based
  if not any? turtles [ report 0 ]
  report mean [ (abs (meme-plus - meme-minus) / 100) ] of turtles
end 

to-report ideologization-opinion-based
  if not any? turtles [ report 0 ]
  report mean [ (abs opinion) * (prevalence / 99) ] of turtles
end 

There is only one version of this model, created 3 days ago by Pierre-Alain Cotnoir.

Attached files

File Type Description Last updated
Simulator_20260316-3_V8.png preview Preview for 'Simulator_20260316-3_V8' 3 days ago, by Pierre-Alain Cotnoir Download

This model does not have any ancestors.

This model does not have any descendants.