Child of Version_20250923-1_Spread of Opinions Influenced by Group Effects and reward plus metablock

No 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.0 • Viewed 22 times • Downloaded 2 times • Run 0 times
Download the 'Child of Version_20250923-1_Spread of Opinions Influenced by Group Effects and reward plus metablock' 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 was developed from research by the Public Opinion Research Group.
It models how opinions on political or social issues spread inside a population, using a multi-agent system.

The first applications focused on modelling the Quebec electorate facing political issues. Surveys revealed a close relationship between voters’ bias level on these issues and the importance of internal representations (or “memes”) underlying their adhesion or rejection.
The simulator reproduces how such bipolar opinions spread and evolve in a connected population.

Agents represent individuals, each carrying: - an opinion (from −1 = strongly against to +1 = strongly in favour), - a prevalence (strength/salience of internal representations), - an influence (capacity to convince others), - and a set of social links.

The model studies the co-evolution of: 1. Individual convictions (opinions), 2. Prevalence (depth/number of representations), 3. Influence (convincing power), 4. Social network structure.


HOW TO USE IT

General operation

  1. Choose the population size with pop.
  2. Press Setup to create agents and their initial links. Background is set to black.
  3. Press Go to run or pause the simulation.

3D Representation

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

Agents are coloured: - Blue → right-leaning opinion,
- Red → left-leaning opinion,
- Yellow → meta-influencers.

Links (ties) are coloured: - Green → agents with same opinion sign,
- Gray → opposite signs.


USER INTERFACE CONTROLS

1. General controls

  • Setup: initialize agents and network.
  • Go: start or stop simulation.
  • in_file: load agent states from a file.
  • refresh / cumulative: control graph refresh and whether stats reset or accumulate.

2. Population and iterations

  • pop: number of agents.
  • nb_try, max_iter, threshold: govern experiment length and repetitions.
  • choice_iter: select iteration when replaying from file.

3. Social network dynamics

Links evolve as opinions shift: - link-removal-threshold: max opinion distance above which links may be cut.
- link-formation-threshold: max distance to allow new links.
- prob: probability applied to link creation/removal.
- linksdown: max number of links removed per tick.
- linksup: max number of links created per tick.
- bridge-prob: probability to create “bridges” across opposing camps.


4. Meta-influencers

Special agents with very high influence (fixed at 1).
- meta-influencers-selection: choose scope (All, Left, Right).
- meta-influencers: proportion of population to turn into meta-influencers.
- prev-low / prev-high: restrict eligible prevalence.
- meta-links, meta-min, meta-max: number of links meta-influencers maintain.
- meta-ok: toggle their presence.
- vary-influence: if ON, influence grows with successful transmissions and decreases with failures.
- metablock: if ON, prevents meta-influencers from changing opinion polarity (sign).


5. Opinion dynamics

Prevalence and influence

  • rate-infl: speed at which influence changes after adoption.
  • modulation-prevalence and rate-modulation: adjust prevalence as opinions shift.
  • noise: probability of random opinion drift.
  • polarization-factor: reduces adoption probability for large opinion gaps.

Adoption probabilities

  • prevalence-weight (0–2 typical): how strongly prevalence gap matters.
  • adoption-floor (0–0.1 typical): minimal adoption probability, even for distant opinions.

6. Group impact

Group alignment modulates adoption probability.

  • group-impact-mode:

    • all → considers all linked neighbours.
    • k-nearest → only the closest k neighbours in opinion space.
  • group-k (1 to number of neighbours): number of neighbours used when k-nearest is active.

  • group-impact-weight (0–1): strength of group effect.

  • group-impact-alpha (0.2–3 typical): non-linearity.

    • <1: small aligned groups have strong effect,
    • =1: linear,
    • >1: only large aligned majorities matter.

7. Reward mechanism

Agents can gain a bonus when they succeed in influencing a neighbour.

  • reward-step (0.01–0.1 typical): increment in transmission bonus.
  • reward-cap (0.1–1.0 typical): maximum bonus an agent can accumulate.
  • reward-scope: apply to both camps, left-only, or right-only.
  • reward-prev-delta (0–5 typical): optional increase of the target’s prevalence after adoption.
  • reward-decay (0–0.05 typical): gradual loss of bonus over time.

8. Meme-based representation

If use-memes? is ON, opinions and prevalence derive from two internal stocks of memes: - meme-plus: representations supporting positive polarity.
- meme-minus: representations supporting negative polarity.

Parameters: - meme-max: maximum stock of memes (scale of prevalence).
- meme-gain: increase in memes when influenced.
- meme-anti-leak (0–1): cross-erosion, reduces opposite stock when one side grows.
- meme-decay (0–0.05 typical): gradual forgetting.

Opinion is recalculated as the balance between meme-plus and meme-minus.
Prevalence reflects the total number of memes held by the agent.


9. External events

Perturb the system through shocks: - Define bounds (low_meme, high_meme, low-prev, high-prev).
- Apply event_size (opinion shift) and prev_change (prevalence shift).
- Trigger manually with Event button or automatically via auto_event + tick-event.


OUTPUTS

Monitors

Show in real time:
- % of left / right,
- medians of opinion, prevalence, influence,
- inversions, interactions, fractal dimension,
- links created/removed.

Graph

Tracks the evolution of population distributions and variables over time.

CSV Export

If csv-export is ON, results are saved per trial with a standardized header.


THINGS TO NOTICE

  • How opinions converge, polarize, or remain fragmented.
  • The role of meta-influencers, group alignment, and reward mechanisms.
  • The impact of memes when enabled.
  • How link dynamics (green vs gray) structure the debate.

CREDITS

  • Original concept: Public Opinion Research Group
  • NetLogo implementation & enhancements: Pierre-Alain Cotnoir (2015–2025)
  • AI-assisted design: GPT-4 & GPT-5 (2024-2025)
  • Contact: pacotnoir@gmail.com

QUICK REFERENCE — CHEAT SHEET

This page summarizes the main controls of the simulator for non-specialists.
Each slider/switch/button is grouped by theme, with recommended value ranges and the effects on the simulation.


Population & Iterations

  • pop → number of agents.
  • nbtry, maxiter, threshold → control repetitions and stopping criteria.
  • choice_iter → load from saved file at selected iteration.

Social Network

  • link-removal-threshold (0–1.0) → above this gap, links may be cut.
  • link-formation-threshold (0–1.0) → below this gap, links may form.
  • prob (0–1.0) → probability for link creation/removal each tick.
  • linksdown / linksup (1–50 typical) → caps on removals/creations per tick.
  • bridge-prob (0–0.3) → chance of links between opposing camps.
    • ↑ value = more bridges, more sign reversals.

Meta-influencers

  • meta-influencers-selection → All / Left / Right.
  • meta-influencers (0–30%) → proportion of metas.
  • prev-low / prev-high → restrict by prevalence.
  • meta-links, meta-min, meta-max → control number of links per meta.
  • meta-ok → enable metas.
  • vary-influence → metas gain influence when successful, lose it when not.
  • metablock → if ON, metas cannot switch sign (they stay Left or Right).

Opinion & Prevalence

  • rate-infl (0–0.1 typical) → speed of influence updates.
  • modulation-prevalence → ON to adjust prevalence with opinion changes.
  • rate-modulation (0–1.0) → how fast prevalence adapts.
  • noise (0–0.1) → probability of random opinion drift.
  • polarization-factor (0–1.0) → reduces adoption across large opinion gaps.
  • prevalence-weight (0–2) → stronger role of prevalence differences.
  • adoption-floor (0–0.1) → minimal chance of adoption, even across divides.

Group Impact

  • group-impact-modeall neighbours or k-nearest.
  • group-k (1–20 typical) → number of neighbours when in k-nearest mode.
  • group-impact-weight (0–1.0) → weight of group effect.
  • group-impact-alpha (0.2–3) → non-linearity:
    • <1 small minorities influence strongly,
    • =1 linear,
    • >1 only large majorities matter.

Reward System

  • reward-step (0.01–0.1) → bonus gained after success.
  • reward-cap (0.1–1.0) → maximum cumulative bonus.
  • reward-scope → both camps / left-only / right-only.
  • reward-prev-delta (0–5) → optional increase of target prevalence.
  • reward-decay (0–0.05) → gradual loss of accumulated bonus.

Meme-Based Representation (if use-memes? ON)

  • meme-max (50–200 typical) → max stock of memes per agent.
  • meme-gain (0.5–2.0) → increment in memes per influence.
  • meme-anti-leak (0–0.5) → erosion of the opposite meme stock.
  • meme-decay (0–0.05) → forgetting rate.

Opinion = balance of meme-plus vs meme-minus.
Prevalence = total memes.


External Events

  • lowmeme / highmeme → opinion bounds.
  • low-prev / high-prev → prevalence bounds.
  • event_size → opinion shift applied.
  • prev_change → prevalence shift.
  • event button → trigger manually.
  • auto_event + tick-event → schedule automatic events.

Display & Outputs

  • show-links? → toggle visibility of ties.
  • linktick (1–5) → link thickness.
  • Monitors → show % left/right, medians, inversions, interactions.
  • Graph → track evolution of proportions over time.
  • CSV Export → save results if csv-export is ON.

QUICK EFFECTS OF KEY SLIDERS

| Slider | Low value effect | High value effect | |----------------------|----------------------------------|--------------------------------| | prevalence-weight | Adoption less tied to prevalence | Prevalence dominates adoption | | adoption-floor | Very few cross-camp adoptions | More random inversions | | bridge-prob | Camps stay separated | Many cross-camp links | | group-impact-weight | Neighbours don’t matter much | Group strongly drives adoption | | group-impact-alpha | Minorities can shift opinions | Only large consensus matters | | reward-step | Slow bonus growth | Fast reinforcement | | reward-decay | Bonus stays long | Bonus fades quickly | | meme-anti-leak | Stocks grow independently | Growth erodes opposite stock |


Comments and Questions

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

Click to Run Model

extensions [sound nw] ;; For using sound and Network package

globals [
  min-prevalence
  max-prevalence
  meta-influencers-droit
  meta-influencers-gauche
  iter change total inversion try major fractale
  ordonnee abcisse profondeur
  list_data file-in in_data repet_data
  links-dead links-create meta-agents meta-links meta-create Interactions %Major

  ;; === CSV export ===
  csv-export
  csv-basename
  csv-file
  csv-open?

  ;; === Paramètres d’inversion / ponts (sliders UI possibles) ===
  ;;prevalence-weight      ;; >= 0 ; amplification du rôle de Δprégnance
  ;;adoption-floor         ;; [0..1] ; plancher minimal pour la pénalité de polarisation
  ;;bridge-prob            ;; [0..1] ; probabilité de créer un lien-pont (opinion éloignée)

  ;; === Paramètres de RÉCOMPENSE (sliders/inputs UI) ===
  ;;reward-step        ;; palier d’augmentation du bonus à chaque succès (ex: 0.05)
  ;;reward-cap         ;; plafond du bonus cumulé (ex: 0.50)
  ;;reward-scope       ;; "both" | "left-only" | "right-only"
  ;;reward-prev-delta  ;; hausse de prégnance du ciblé au succès (ex: 0..5), 0 = off
  ;;reward-decay       ;; décroissance du bonus par tick (ex: 0..0.01), 0 = off
]

turtles-own [
  opinion         ;; [-1, 1]
  prevalence      ;; [min-prevalence, max-prevalence]
  agent-type      ;; "Right side" | "Left side"
  influence       ;; [0, 1]
  opinion-previous
  influence-previous
  x3d y3d z3d

  ;; Mèmes (stock pro/anti)
  meme-plus
  meme-minus

  ;; variables utilitaires
  old-opinion
  proposed-opinion

  ;; Récompense de transmission (bonus multiplicatif p-adopt côté émetteur)
  tx-bonus
]

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

to setup
  clear-all
  set repet_data false
  set iter 0
  set min-prevalence 0
  set max-prevalence 99
  set-default-shape turtles "person"
  set try 1
  set major 0
  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 [ set meta-links meta-min ]

  ;; === Defaults CSV ===
  if not is-boolean? csv-export [ set csv-export false ]
  if (not is-string? csv-basename) or (csv-basename = "") [ set csv-basename "run" ]
  set csv-open? false

  ;; === Defaults IMPACT DE GROUPE ===
  if (not is-string? group-impact-mode) [ set group-impact-mode "all" ]    ;; "all" | "k-nearest"
  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 ]

  ;; === Default switches ===
  if not is-boolean? show-links? [ set show-links? false ]
  if not is-boolean? metablock   [ set metablock false ]

  ;; === Defaults inversion/ponts ===
  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 ]

  ;; === Defaults REWARD ===
  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 ]

  ;; === Defaults MEMES ===
  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 ]

  set-background-black

  create
  rapport
end 

to create
  ;; Right side
  create-turtles pop / 2 [
    set agent-type "Right side"
    set opinion random-float 1                     ;; (0,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

    ;; init mèmes cohérente avec (prevalence, opinion)
    let tot initial-prevalence-to-memes prevalence
    ifelse opinion >= 0 [
      set meme-plus  tot * (0.5 + 0.5 * abs opinion)
      set meme-minus tot - meme-plus
    ] [
      set meme-minus tot * (0.5 + 0.5 * abs opinion)
      set meme-plus  tot - meme-minus
    ]
    update-3d self
  ]

  ;; Left side
  create-turtles pop / 2 [
    set agent-type "Left side"
    set opinion (random-float 1 - 1)               ;; (-1,0)
    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

    ;; init mèmes cohérente avec (prevalence, opinion)
    let tot initial-prevalence-to-memes prevalence
    ifelse opinion >= 0 [
      set meme-plus  tot * (0.5 + 0.5 * abs opinion)
      set meme-minus tot - meme-plus
    ] [
      set meme-minus tot * (0.5 + 0.5 * abs opinion)
      set meme-plus  tot - meme-minus
    ]
    update-3d self
  ]

  ;; Méta-influenceurs initiaux
  influenceurs

  reset-ticks

  set total 0
  set change 0
  set Interactions 0
  set %Major 0
  update-networks

  recolor-links
  apply-link-visibility
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SORTIES / RAPPORT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to rapport
  if output = "Statistics" [
    output-print (word
      "Try ; " "Iter ; "
      "Opinion global ; "
      "Opinion right side ; "
      "Opinion left side ; "
      "Prevalence right side ; "
      "Prevalence left side ; "
      "Influence right side ; "
      "Influence left side ; "
      "Left % ; "  "Right % ; "
      "Links-Remove ; " "Links-Create ; "
      "Inversion % ; " "change ; " "total ; " "fractale")
  ]
  if output = "Values" [
    output-print (word "Try ; " "Ticks ; "  "Agents ; "
                        "Prevalence ; " "Opinion ; " "Influence ; " "meme droit")
  ]

  if output = "File" [
    ask turtles [
      let pre prevalence
      let mem opinion
      let infl influence
      let ti ticks
      output-print (word ti " " pre " " mem " " infl)
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; META-INFLUENCEURS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to influenceurs
  ;; All
  if meta-influencers-selection = "All" [
    let k round (count turtles * meta-influencers / 100)
    if k > 0 [
      ask n-of k turtles [
        if (prevalence >= prev-low and prevalence <= prev-high) [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]
  ]
  ;; Right side
  if meta-influencers-selection = "Right side" [
    set meta-influencers-droit round (count turtles * meta-influencers / 100)
    let candidates turtles with [opinion > 0]
    let k min list meta-influencers-droit count candidates
    if k > 0 [
      ask n-of k candidates [
        if (prevalence > prev-low and prevalence <= prev-high) [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]
  ]
  ;; Left side
  if meta-influencers-selection = "Left side" [
    set meta-influencers-gauche round (count turtles * meta-influencers / 100)
    let candidates turtles with [opinion < 0]
    let k min list meta-influencers-gauche count candidates
    if k > 0 [
      ask n-of k candidates [
        if (prevalence > prev-low and prevalence <= prev-high) [
          set influence 1
          set color yellow
          set meta-agents meta-agents + 1
        ]
      ]
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; OUTILS MÉTA / VETO
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Un agent est "méta" s'il est jaune OU si son influence vaut 1

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

;; Change l'opinion en respectant le veto méta quand metablock = true.
;; Solution 1 (renforcement sans inversion) :
;; - si la nouvelle opinion change le signe d’un méta alors que metablock=ON,
;;   on conserve le signe ACTUEL et on prend la magnitude MAX(abs(old), abs(new)).

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 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; BOUCLE PRINCIPALE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to go
  ifelse (iter < max_iter) [
    if iter > 0 [ set Interactions (total / iter) ]
    if iter > 0 [ set %Major (major / iter * 100) ]
    set iter iter + 1
    set meta-create 0

    if (iter = 1 and csv-export and not csv-open?) [ csv-begin ]

    if auto_event = true [
      if (tick-event = iter) [ event ]
    ]
    if meta-ok = true [ meta ]

    update-opinions
    if network = true [ update-networks ]
    recolor-links
    apply-link-visibility

    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 (word try " ; " ti " ; " avg-opinion " ; "
                        positive-opinion " ; " negative-opinion " ; "
                        positive-prevalence " ; " negative-prevalence " ; "
                        positive-influence " ; " negative-influence " ; "
                        Left% " ; " Right% " ; "
                        links-dead " ; " links-Create " ; "
                        inversion " ; " change " ; " total " ; " fractale)
    ]

    tick

    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
    ]

    if csv-export [ csv-row ]

  ] [
    ifelse (try < nb_try) [
      if csv-export [ csv-end ]

      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
      ifelse (repet_data = true) [
        data
      ] [
        create
        set meta-links meta-min
      ]
    ] [
      if csv-export [ csv-end ]
      sound:play-note "Tubular Bells" 60 64 1
      stop
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MISE À JOUR DES OPINIONS (effet de groupe + récompenses + mèmes + veto méta)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-opinions
  ask turtles [
    set opinion-previous opinion
    let target one-of link-neighbors
    if target != nobody [
      ;; Δprégnance (tolérance 1)
      let raw-dprev ([prevalence] of target) - prevalence
      if raw-dprev < 1 [ set raw-dprev 0 ]
      let dprev raw-dprev / max-prevalence

      if dprev > 0 [
        ;; distance mémique en valeur absolue des signes
        let dmem abs(abs(opinion) - abs([opinion] of target))

        ;; base-prob + pénalité de polarisation
        let base-prob dprev * prevalence-weight
        let pol-penalty max list adoption-floor (1 - polarization-factor * dmem)

        ;; probabilité brute (sans groupe), pondérée par influence & tx-bonus de l’émetteur
        let p-adopt base-prob * pol-penalty * [influence] of target * (1 + [tx-bonus] of target)

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

        ;; borne [0,1]
        if p-adopt < 0 [ set p-adopt 0 ]
        if p-adopt > 1 [ set p-adopt 1 ]

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

          ifelse use-memes? [
            ;; renforcement des mèmes du receveur selon le signe de l’émetteur
            transmit-memes target
            ;; opinion & prevalence dérivées des mèmes (protégées par metablock)
            recompute-from-memes
          ] [
            ;; adoption « historique » protégée par veto
            maybe-set-opinion proposed-opinion
          ]

          ;; si veto/reflexion n’a pas modifié le signe et que rien n’a changé → pas de reward
          if opinion = old-opinion [ stop ]

          ;; succès de transmission
          set total total + 1

          ;; récompense à l’émetteur si éligible
          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))
            ]
          ]

          ;; option : hausse de prégnance du ciblé
          if reward-prev-delta > 0 [
            set prevalence min (list max-prevalence (prevalence + reward-prev-delta))
          ]

          ;; dynamique d’influence (logique existante)
          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) [
                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) [
                if meta-ok = true [
                  set meta-agents meta-agents - 1
                  ifelse opinion >= 0 [ set color blue ] [ set color red ]
                ]
              ]
            ]
          ]

          ;; comptage des inversions (si non bloquée par veto/réflexion)
          if (sign old-opinion) != (sign opinion) [
            set change change + 1
          ]
        ]
      ]
    ]

    ;; modulation de la prévalence
    if modulation-prevalence = true [
      if prevalence > abs opinion * 100 [
        set prevalence prevalence - abs(opinion - opinion-previous) * influence * Rate-modulation
      ]
      if prevalence < abs opinion * 100 [
        set prevalence prevalence + abs(opinion - opinion-previous) * influence * Rate-modulation
      ]
      if prevalence < min-prevalence [ set prevalence min-prevalence ]
      if prevalence > max-prevalence [ set prevalence max-prevalence ]
    ]

    ;; bruit additif (protégé par veto/réflexion)
    if random-float 1 < noise [
      let delta (random-float 0.4 - 0.2)
      maybe-set-opinion (opinion + delta)
    ]

    ;; décroissance des mèmes éventuelle
    if use-memes? [ decay-memes ]

    ;; update 3D
    update-3d self

    ;; logging
    if (output = "Values" or output = "File") [
      compute-statistics
    ]
  ]

  ;; décroissance du bonus (optionnelle)
  if reward-decay > 0 [
    ask turtles [
      set tx-bonus max (list 0 (tx-bonus - reward-decay))
    ]
  ]

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COLORATION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MISE À JOUR DU RÉSEAU (suppression/formation + ponts)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-networks
  ;; suppression
  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
  ]

  ;; formation
  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 [
    let pool other turtles with [
      color = yellow and
      not link-neighbor? myself and
      (count link-neighbors) < meta-links
    ]
    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 apply-link-visibility
  ifelse show-links? [
    ask links [ show-link ]
  ] [
    ask links [ hide-link ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STATISTIQUES RUNTIME
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to compute-statistics
  if output = "Values" [
    let pre prevalence
    let mem opinion
    let infl influence
    let ag who
    let ti ticks
    let ess try
    let memed (count turtles with [opinion > 0]) / (pop / 100)
    let maj major
    output-print (word ess " ; " ti " ; "  ag " ; " pre " ; "  mem " ; " infl " ; " memed)
  ]
  if output = "File" [
    let pre prevalence
    let mem opinion
    let infl influence
    let ti ticks
    output-print (word ti " " pre " " mem " " infl)
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; I/O : LECTURE FICHIER D’AGENTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to in_file
  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
      user-message "File uploaded!"
      set in_data true
    ]
  ] [
    user-message "File read error"
  ]
  data
end 

to data
  clear-turtles
  clear-links
  let tick_to_load choice_iter

  ifelse (is-list? list_data) [
    let filtered_data filter [ row -> first row = tick_to_load ] list_data

    create-turtles length filtered_data [
      let my_index who
      let agent_data item my_index filtered_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

      if opinion < 0 [ set color red  set agent-type "Left side"  ]
      if opinion > 0 [ set color blue set agent-type "Right side" ]
      if influence = 1 [ set color yellow ]

      ;; init mèmes en cohérence
      let tot initial-prevalence-to-memes prevalence
      ifelse opinion >= 0 [
        set meme-plus  tot * (0.5 + 0.5 * abs opinion)
        set meme-minus tot - meme-plus
      ] [
        set meme-minus tot * (0.5 + 0.5 * abs opinion)
        set meme-plus  tot - meme-minus
      ]

      update-3d self
    ]
  ] [
    set in_data false
    user-message "Read error"
  ]

  update-networks
  apply-link-visibility
  recolor-links

  influenceurs
  update-opinions
  set repet_data true
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ÉVÉNEMENT EXTERNE (protégé par veto/réflexion)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to event
  ask turtles [
    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)) ]
        ]
      ]
    ]
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; UTILITAIRES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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 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 

;; IMPACT DE GROUPE (tous les voisins liés)

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 

;; IMPACT DE GROUPE (k plus proches)

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 

;; Sélecteur de mode

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 

;; Mapping prevalence -> stock initial de mèmes

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

;; Recalcule opinion & prevalence à partir des mèmes (protégé par veto/réflexion)

to recompute-from-memes
  let tot meme-plus + meme-minus
  if tot < 1e-6 [ set tot 1e-6 ]
  set proposed-opinion ((meme-plus - meme-minus) / tot)
  maybe-set-opinion proposed-opinion
  let scaled  (tot / meme-max) * 99
  if scaled < 0 [ set scaled 0 ]
  if scaled > 99 [ set scaled 99 ]
  set prevalence scaled
end 

;; Décroissance des mèmes

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

;; Transmission des mèmes d’un émetteur vers le receveur (self)

to transmit-memes [emitter]
  let sgn sign [opinion] of emitter
  ifelse sgn >= 0 [
    set meme-plus  meme-plus + meme-gain
    set meme-minus max list 0 (meme-minus - meme-anti-leak * meme-gain)
  ] [
    set meme-minus meme-minus + meme-gain
    set meme-plus  max list 0 (meme-plus - meme-anti-leak * meme-gain)
  ]
  ;; plafonner en douceur
  let tot meme-plus + meme-minus
  if tot > meme-max [
    let factor meme-max / tot
    set meme-plus  meme-plus  * factor
    set meme-minus meme-minus * factor
  ]
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; EXPORT CSV (par essai)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to csv-begin
  if not csv-export [ stop ]
  set csv-file (word csv-basename "-" try ".csv")
  file-close-all
  if file-exists? csv-file [ file-delete csv-file ]
  file-open csv-file
  set csv-open? true
  file-print "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,inversion_pct,change,total,fractale,major"
end 

to csv-row
  if not csv-open? [ stop ]
  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)
  file-print (word try "," iter "," ticks ","
              leftpct "," rightpct "," avg-opinion ","
              opR "," opL "," prevR "," prevL ","
              inflR "," inflL ","
              links-dead "," links-create ","
              inversion "," change "," total "," fractale "," major)
end 

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

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

Attached files

No files