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

Version_20250923-1_Spread of Opinions Influenced by Group Effects and reward plus metablock 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 25 times • Downloaded 14 times • Run 0 times
Download the '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 designed 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.

This work has focused on modelling the Quebec electorate facing political issues. Surveys have revealed the close relationship among the electorate between the bias level on these issues and the importance of representations underlying the accession of voters to these issues, i.e., the significance of this adhesion for each of the voters.

The operation of this multi-agent simulator is established on this relationship. It models the transmission in a population of a bipolar view.

Four factors are used to simulate the rules of meme transmission: prevalence, polarization of opinion, influence and social links.

  • Prevalence simulates the quality and quantity of neural representations an individual could have about an opinion or meme.
  • Influence is the ability of individuals to transmit their meme.
  • Social links simulate the relations of proximity or randomness among individuals sharing similar memes or having antagonistic opinions.

Agents carry: - an opinion (−1 to +1), - a prevalence (strength/salience), - an influence (capacity to convince), - and a set of social links.

The model studies the co-evolution of: 1. Individual convictions, 2. Salience of issues (prevalence), 3. Influence capacities, 4. Social network structure.


HOW TO USE IT

Basic operation

  1. Choose the population size in pop.
  2. Press Setup to generate agents and their initial links (with a black background).
  3. Press Go to run or pause the simulation.

Agents in 3D: - X axis: opinion (–1 = left, +1 = right),
- Y axis: prevalence (0–99),
- Z axis: influence (0–1).

Links (ties) are coloured: - Green: both agents share the same sign (homophily),
- Gray: opposite signs (bridges).

Their thickness is set by the slider linktick.
Use the show-links? switch to show/hide ties.


Social network dynamics

Links are continuously created or removed depending on opinion distance:

  • link-removal-threshold — maximum opinion gap above which a link can be deleted,
  • link-formation-threshold — maximum gap to allow forming new ties,
  • prob — probability applied to link removal/creation,
  • linksdown — max number of links removed per tick,
  • linksup — max number of links created per tick.

Bridges between opposing camps may also form with the bridge-prob slider (see below).


Loading data

Use in_file to import a text file (space-separated):

choice_iter selects which iteration to load.
This lets you replay or branch from a saved configuration.


Meta-influencers

Create highly influential agents (influence = 1):

  • Choose the scope with meta-influencers-selection (All, Left, Right).
  • Set their proportion via meta-influencers.
  • Restrict eligibility with prev-low / prev-high.
  • Control extra ties with meta-links, meta-min, meta-max.
  • If vary-influence is ON, a meta-influencer’s influence grows if it successfully convinces a target, but decreases if it fails.
  • meta-ok toggles their participation; an Influent button can add them at runtime.

🔒 metablock — Locking Meta-Influencers’ Polarity

This switch allows you to anchor meta-influencers so they cannot cross from one opinion polarity to the other (left ↔ right).

  • OFF (false): meta-influencers behave like regular agents. They may change polarity (blue ↔ red) if adoption dynamics push them across the neutral point.
  • ON (true): meta-influencers are locked in their initial camp. They can still influence others and adjust their prevalence or influence level, but their sign (Left/Right) will never flip.

Why use it? - To model anchored leaders or core elites who remain stable symbols for one camp.
- To explore the difference between flexible leadership (switching sides possible) and fixed leadership (anchored, polarity preserved).


NEW & ENHANCED FEATURES

  • 3D view: agents plotted by opinion (X), prevalence (Y), influence (Z).
  • Dynamic links: created/removed as opinions evolve.
  • Link colouring:
    • Green → same-signed opinions,
    • Gray → opposite signs (including meta-influencers).
  • Meta-influencer links with limits (meta-minmeta-max).
  • Prevalence modulation and noise built into adoption rules.
  • CSV export per trial: logs statistics at every tick.
  • Toggle show-links? to display/hide connections.
  • Background set to black automatically at setup.

Group impact parameters

These sliders control how the alignment of an agent’s neighbours modulates adoption probability.

group-impact-weight

Strength of group influence.
Range: 0 (none) → 1 (full).

group-k

Number of neighbours considered in "k-nearest" mode.
- 1–3: only closest peers matter.
- 5–10: moderate neighbourhood effect.
- Large values: approximate "all" mode.

group-impact-alpha

Non-linearity of the effect:
[ f(g) = g^{\alpha} ]

  • α = 1 → linear,
  • α < 1 → concave (small aligned groups have strong effect),
  • α > 1 → convex (only large aligned groups matter).

Reward System

The Reward system increases the chance of successful influence when an agent convinces a neighbour:

  • reward-step: increment added to the influencer’s transmission bonus (tx-bonus) after each success.
  • reward-cap: maximum bonus allowed. Prevents runaway effects.
  • reward-scope: applies the reward to both, left-only, or right-only influencers.
  • reward-prev-delta: if >0, the target’s prevalence is increased each time it adopts.
  • reward-decay: gradual reduction of accumulated bonus at each tick (default 0 = no decay).

This system rewards consistent influencers and models reinforcement learning dynamics.


Additional parameters: prevalence-weight, adoption-floor, bridge-prob

prevalence-weight — Weight of prevalence in adoption

Controls how much the prevalence gap between a target and its neighbour affects adoption probability.

adoption-floor — Minimum adoption probability

Sets a floor for adoption, even if opinion distance or influence would make adoption nearly impossible.

bridge-prob — Probability of cross-camp links

Introduces random bridge links between agents of opposite signs, bypassing the formation threshold.


USER INTERFACE CONTROLS

General commands

  • Setup — initialize agents & network
  • Go — run/pause
  • in_file — load agent file
  • auto_event — schedule events at tick-event
  • refresh / cumulative — control graph refresh & stat accumulation

Population & iterations

pop, nb_try, max_iter, threshold, tick-event

External events

event, On_to_left, meme_set, event_size, prev_change

Meta-influencers

meta-influencers, meta-influencers-selection, meta-links, meta-min, meta-max, prev-low, prev-high, vary-influence, meta-ok, metablock

Opinion & prevalence

rate-infl, modulation-prevalence, rate-modulation, noise, polarization-factor

Social network

prob, linksdown, linksup, link-removal-threshold, link-formation-threshold, bridge-prob

Group impact

group-impact-weight, group-impact-alpha, group-k, group-impact-mode (all / k-nearest)

Reward system

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

Links & display

show-links?, linktick
Colours: green = same sign, gray = opposite.

Monitors & graph

  • Monitors: % left/right, medians (opinion, prevalence, influence), inversions, interactions, fractal dimension, link stats.
  • Graph: tracks proportions and variables over time.

THINGS TO NOTICE

  • How opinions converge or polarize based on prevalence, influence, reward and network evolution.
  • The role of meta-influencers and neighbour alignment in adoption.
  • Link colours: green for homophily, gray for cross-camp ties.
  • Adjusting prevalence-weight, adoption-floor, bridge-prob, and metablock helps control the stability of opinion clusters.

NETLOGO FEATURES

  • 3D visualization of agents & links.
  • Export results via file or CSV.

CREDITS AND REFERENCES

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

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 (peuvent être des sliders UI) ===
  ;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 possibles) ===
  ;;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  ;; augmentation de la 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
  ;; Coordonnées 3D propres à chaque agent
  x3d y3d z3d

  ;; === Récompense de transmission ===
  tx-bonus        ;; bonus multiplicatif sur p-adopt quand la tortue est ÉMETTEUR (≥ 0)
]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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 si widgets pas encore ajoutés ===
  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 (si widgets absents) ===
  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 ]  ;; 0..1
  if (not is-number? group-impact-alpha) [ set group-impact-alpha 1.0 ]    ;; >=0.1

  ;; === Default show-links? & metablock si widgets absents ===
  if not is-boolean? show-links? [ set show-links? false ]
  if not is-boolean? metablock   [ set metablock false ]

  ;; === Defaults inversions/ponts (si pas de sliders) ===
  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 (si pas de sliders) ===
  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" ]     ;; "both"|"left-only"|"right-only"
  if not is-number? reward-prev-delta [ set reward-prev-delta 0 ]     ;; 0 = désactivé
  if not is-number? reward-decay      [ set reward-decay 0 ]          ;; 0 = pas de décroissance

  set-background-black

  create
  rapport
end 

to create
  ;; Créer les agents 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
    update-3d self
  ]

  ;; Créer les agents 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
    update-3d self
  ]

  ;; Création des méta-influenceurs (selon vos réglages UI)
  influenceurs

  reset-ticks

  ;; Initialisation réseau via vos règles (créera des liens si conditions réunies)
  set total 0
  set change 0
  set Interactions 0
  set %Major 0
  update-networks

  ;; Colorer/afficher les liens dès l’initialisation
  recolor-links
  apply-link-visibility
end 

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

to rapport
  ;; titles for Statistics or Values inside compute-statistics
  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.
;; Si le changement est bloqué, on ne touche pas à opinion.

to maybe-set-opinion [ new-op ]
  let old-op opinion
  ;; borne de sécurité
  let bounded-op max list -1 min list 1 new-op

  if metablock and meta? and (sign old-op != sign bounded-op) [
    stop   ;; veto: ne rien changer
  ]

  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  ;; plafond de création de liens autour des méta-influenceurs par tick

    ;; Ouvrir le CSV au premier tick de l’essai
    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   ;; montrer/cacher les liens selon show-links?

    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

    ;; “Fractale” via changement de base sûr
    if (change > 1 and total > 1) [
      set fractale (ln total) / (ln change)
    ]

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

    colorer

    ;; rafraîchir le graphique
    if (refresh = true) [
      if ticks > 200 [ reset-ticks clear-plot ]
    ]

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

    ;; Écrire une ligne CSV par tick
    if csv-export [ csv-row ]

  ] [
    ifelse (try < nb_try) [
      ;; Fin d’essai: fermer le CSV de l’essai courant
      if csv-export [ csv-end ]

      ;; réinitialisation pour l’essai suivant
      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
      ]
    ]
    [
      ;; Fin de toutes les répétitions: fermer CSV si encore ouvert
      if csv-export [ csv-end ]
      sound:play-note "Tubular Bells" 60 64 1
      stop
    ]
  ]
end 

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

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

      if dprev > 0 [
        ;; distance sur le signe absolu (favorise des inversions quand Δprégnance est fort)
        let dmem abs(abs(opinion) - abs([opinion] of target))

        ;; base-prob amplifiée par prevalence-weight
        let base-prob dprev * prevalence-weight

        ;; pénalité de polarisation bornée par adoption-floor
        let pol-penalty max list adoption-floor (1 - polarization-factor * dmem)

        ;; probabilité de base (sans groupe)
        let p-adopt base-prob * pol-penalty * [influence] of target

        ;; BONUS de l'émetteur : c’est le voisin 'target'
        set p-adopt p-adopt * (1 + [tx-bonus] of target)

        ;; effet de groupe (voisins du RECEVEUR alignés avec le SIGNE de l'émetteur)
        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)))

        ;; garde-fous
        if p-adopt < 0 [ set p-adopt 0 ]
        if p-adopt > 1 [ set p-adopt 1 ]

        ;; --- tirage d'adoption ---
        if random-float 1 < p-adopt [
          let old-opinion opinion
          let proposed-opinion [opinion] of target

          ;; tentative avec VETO centralisé
          maybe-set-opinion proposed-opinion

          ;; si veto bloqué: rien ne change (pas de reward, pas d’inversion)
          if opinion = old-opinion [ stop ]

          ;; adoption acceptée
          set total total + 1

          ;; RÉCOMPENSE à l'émetteur (target) 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)
          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 méta)
    if random-float 1 < noise [
      let delta (random-float 0.4 - 0.2)
      maybe-set-opinion (opinion + delta)
    ]

    ;; mise à jour position 3D
    update-3d self

    ;; logging fin de boucle agent
    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 % (après la boucle)
  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 (robuste + ponts + coloration + switch show-links?)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to update-networks
  ;; suppression de liens
  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 de liens
  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
  ;; 1) On n'agit pas si le réseau est gelé
  if not network [ stop ]

  ;; 2) Pour chaque agent, tenter un lien vers un méta
  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

      ;; couleur/épaisseur cohérentes
      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 

;; Applique la visibilité globale des liens selon le switch show-links?

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STATISTIQUES RUNTIMES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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  ;; File d'entrée
  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 ]

      ;; Position initiale (2D/3D)
      update-3d self
    ]
  ] [
    set in_data false
    user-message "Read error"
  ]

  ;; créer des liens selon vos règles
  update-networks
  apply-link-visibility
  recolor-links

  influenceurs
  update-opinions
  set repet_data true
end 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ÉVÉNEMENT EXTERNE (protégé par veto via maybe-set-opinion)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to event  ;; moving agents to the right or left side by increasing or decreasing the prevalence
  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)
;; Retourne la proportion de voisins liés dont le signe d'opinion = sign-ref.
;; Si aucun voisin lié : retourne 0.5 (neutre).
;; ---------------------------------------------------------------------------

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 en opinion)
;; Choisit les k voisins liés les plus proches en opinion de agt,
;; puis renvoie la même proportion (même signe = sign-ref).
;; Si aucun voisin lié : 0.5 (neutre).
;; ---------------------------------------------------------------------------

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 

;; ---------------------------------------------------------------------------
;; IMPACT DE GROUPE EFFECTIF selon le mode sélectionné ("all" | "k-nearest")
;; ---------------------------------------------------------------------------

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 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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
  ;; En-tête standardisé
  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 are 4 versions of this model.

Uploaded by When Description Download
Pierre-Alain Cotnoir 15 days ago New settings for sliders and one bug corrrected Download this version
Pierre-Alain Cotnoir 15 days ago Complete rewriting of Info Download this version
Pierre-Alain Cotnoir 15 days ago Updated Info Download this version
Pierre-Alain Cotnoir 15 days ago Initial upload Download this version

Attached files

File Type Description Last updated
Version_20250923-1_Spread of Opinions Influenced by Group Effects and reward plus metablock.png preview Preview for 'Version_20250923-1_Spread of Opinions Influenced by Group Effects and reward plus metablock' 15 days ago, by Pierre-Alain Cotnoir Download