DOI: 10.5061/dryad.dfn2z34xd
title: Honest signalling of cooperative intentions

description: Trust can transform conflicting interests into cooperation. But how can
 individuals know when to trust others? Here, I develop the theory that
 reputation building may signal cooperative intent, or ‘trustworthiness’. I
 model a simple representation of this theory in which individuals (1)
 optionally invest in a reputation by performing costly helpful behaviour
 (‘signalling’); (2) optionally use others’ reputations when choosing a
 partner; and (3) optionally cooperate with that partner. In evolutionary
 simulations, high levels of reputation building; of choosing partners
 based on reputation; and of cooperation within partnerships emerged.
 Costly helping behaviour evolved into an honest signal of trustworthiness
 when it was adaptive for cooperators, relative to defectors, to invest in
 the long-term benefits of a reputation for helping. I show using game
 theory that this occurs when cooperators gain larger marginal benefits
 from investing in signalling than do defectors. This happens without the
 usual costly signalling assumption that individuals are of two ‘types’
 which differ in quality. Signalling of trustworthiness may help explain
 phenomena such as philanthropy, pro-sociality, collective action,
 punishment, and advertising in humans and may be particularly applicable
 to courtship in other animals.
description: The data were produced
 using evolutionary simulation programs. Source code, data files and R code
 are described here. <b>Figure
 3a,b</b> Run source code file RBPC.c (in
 Visual Studio 2017 or modify appropriately for other complier)
 Check parameters are
 population size N = 100; generations = 1000; islands i = 10; cost c=1;
 benefit b = 10; meetings m = 50; rounds r = 25; signal cost s = 10; cost
 of choice h = 0.01; baseline payoff = 1000; mutation rate µ= 0.02
 (parameters are explained in Table S1). This outputs a simulation data
 file named dynamics.dat. For clarity I upload this as Fig3ab.dat
 To produce Figures 3a and
 b, read this data file into Rstudio and name the data frame “dynamics”, as
 follows: &gt;library(ggplot2) &gt;attach(dynamics) &gt;mdynamics &lt;- aggregate(dynamics, by=list(V2, V3, V4), FUN=mean) &gt; mdynamicsrole1 &lt;- subset(mdynamics, V3==1, select=c("V2", "V4", "V5", "V6")) &gt; ggplot(mdynamicsrole1g100, aes(x=V2, y=V5, colour=as.factor(V4)))+geom_line() + theme(plot.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.border = element_blank(), panel.background = element_blank(), axis.line = element_line(colour = 'black'), axis.title.x=element_text(size=19, colour='black'), axis.title.y = element_text(size=19, colour='black'), axis.text.x = element_text(size=12, colour='black'), axis.text.y = element_text(size=12, colour='black'), legend.text = element_text(size=12), legend.title=element_blank(), legend.background = element_rect(colour='black', size=.5, linetype="solid"), legend.position=c(.75,.5)) +labs(x='Generation', y='Strategy (%)') + scale_colour_discrete(breaks=c("0", "1", "2", "3"), labels=c("No signal, D", "No signal, C", "Signal, D", "Signal, C" )) &gt;mdynamicsrole0 &lt;- subset(mdynamics, V3==0, select=c("V2", "V4", "V5", "V6")) &gt;mdynamicsrole0g100 &lt;- subset(mdynamicsrole0, V2 &lt; 100, select=c("V2", "V4", "V5", "V6")) &gt; ggplot(mdynamicsrole0g100, aes(x=V2, y=V5, colour=as.factor(V4)))+geom_line() + theme(plot.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.border = element_blank(), panel.background = element_blank(), axis.line = element_line(colour = 'black'), axis.title.x=element_text(size=19, colour='black'), axis.title.y = element_text(size=19, colour='black'), axis.text.x = element_text(size=12, colour='black'), axis.text.y = element_text(size=12, colour='black'), legend.text = element_text(size=12), legend.title=element_blank(), legend.background = element_rect(colour='black', size=.5, linetype="solid"), legend.position=c(.75,.5)) +labs(x='Generation', y='Strategy (%)') + scale_colour_discrete(breaks=c("0", "1", "2", "3"), labels=c("Any, D", "Any, C", "Choose, D", "Choose, C" ))   <b>Figure 3c</b> To produce this figure, run the RBPC.c source code file modified to write separate lines for the total proportions of Signalers, Choosers and Cooperators in each generation. This file is uploaded as Read this file into RStudio as dynamicsschc.dat. Load this into Rstudio and use the following to obtain the Figure: &gt;mschc &lt;- aggregate(dynamicsschc, by=list(V2, V4), FUN=mean) &gt;mschc100 &lt;- subset(mschc, V2 &lt; 100, select=c("V2", "V3", "V4")) &gt;ggplot(mschc100, aes(x=V2, y=V3, colour=as.factor(V4)))+geom_line() + theme(plot.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.border = element_blank(), panel.background = element_blank(), axis.line = element_line(colour = 'black'), axis.title.x=element_text(size=19, colour='black'), axis.title.y = element_text(size=19, colour='black'), axis.text.x = element_text(size=12, colour='black'), axis.text.y = element_text(size=12, colour='black'), legend.text = element_text(size=12), legend.title=element_blank(), legend.background = element_rect(colour='black', size=.5, linetype="solid"), legend.position=c(.75,.5)) + labs(x='Generation', y='Strategy (%)') + scale_colour_discrete(breaks=c("1", "2", "3"), labels=c("Signal", "Choose", "Cooperate"))   <b>Figure 4</b> Run source code RBPC.c modified to output the probability of signalling given that an agent is a co-operator [p(S|C] versus a defector [p(S|D)]. Import the data file pscpsd.dat into RStudio and aggregate it across simulations by generation and probabilities then plot as follows: &gt;mpscpsd &lt;- aggregate(ppscpsd, by=list(v2, V4), FUN=mean) &gt;ggplot(mpscpsd, aes(x=V2, y=V3, colour=as.factor(V4)))+geom_line() + theme(plot.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.border = element_blank(), panel.background = element_blank(), axis.line = element_line(colour = 'black'), axis.title.x=element_text(size=19, colour='black'), axis.title.y = element_text(size=19, colour='black'), axis.text.x = element_text(size=12, colour='black'), axis.text.y = element_text(size=12, colour='black'), legend.text = element_text(size=12), legend.title=element_blank(), legend.background = element_rect(colour='black', size=.5, linetype="solid"), legend.position=c(.75,.75)) + labs(x='Generation', y='Probability') + scale_colour_discrete(breaks=c("1", "2"), labels=c("p(S|C)", "p(S|D)")) Similarly, for p(C|S) and p(C|no-S), read in file pcspcns, aggregate and plot: &gt;mpcspcns &lt;- aggregate(pcspcns, by=list(v2, V4), FUN=mean) &gt;ggplot(mpcspcns, aes(x=V2, y=V3, colour=as.factor(V4)))+geom_line(size=1.2) + theme(plot.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.border = element_blank(), panel.background = element_blank(), axis.line = element_line(colour = 'black'), axis.title.x=element_text(size=20, colour='black'), axis.title.y = element_text(size=20, colour='black'), axis.text.x = element_text(size=14, colour='black'), axis.text.y = element_text(size=14, colour='black'), legend.text = element_text(size=14), legend.title=element_blank(), legend.background = element_rect(colour='black', size=.5, linetype="solid"), legend.position=c(.75,.25)) + labs(x='Generation', y='Probability') + scale_colour_discrete(breaks=c("1", "2"), labels=c("p(C|S)", "p(C|no S)"))   <b>Figure 6</b> Run RBPC.c source code with output as in Figure 3c of proportions displaying ‘Choose’ strategies; the proportion signalling; and the proportion cooperating. In each case these are calculated as means with standard errors of the given variable value in generation 100, computed across 10 simulations For Figure6a-c, vary signal cost whilst keeping other parameters constant (see Figure 3 Legend for parameters) on the. They are therefore intended to indicate the average value at equilibrium (see Figure 3 for how the evolutionary dynamics reach equilibrium value within 100 generations). Similarly panels d-f show average percentages of Signallers, Choosers and Cooperators keeping other parameters constant (as in Figure 3) while varying the number of plays as the primary means of increasing the benefits of a relationship with a partner. These data are summarized in the files parastats.xls and playstats.xls. Use the following to plot: &gt;ggplot(parastats, aes(x=signalcost, y=coopm)) + geom_point(stat="identity") + geom_errorbar(aes(ymin=coopselo, ymax=coopsehi), width = 2, size = 1) + labs(x='Signal Cost', y='Cooperators (%)') + ylim(0,100)+ theme(plot.background=element_blank(), panel.background=element_blank(), panel.grid.major=element_blank(), panel.grid.minor=element_blank(), axis.line=element_line(colour='black'), axis.title.x=element_text(size=22, colour='black'), axis.title.y = element_text(size=22, colour='black'), axis.text.x = element_text(size=14, colour='black'), axis.text.y = element_text(size=14, colour='black')) &gt; ggplot(parastats, aes(x=signalcost, y=signal)) + geom_point(stat="identity") + geom_errorbar(aes(ymin=signallo, ymax=signalhi), width = 2, size = 1) + labs(x='Signal Cost', y='Signallers (%)') + ylim(0,100)+ theme(plot.background=element_blank(), panel.background=element_blank(), panel.grid.major=element_blank(), panel.grid.minor=element_blank(), axis.line=element_line(colour='black'), axis.title.x=element_text(size=22, colour='black'), axis.title.y = element_text(size=22, colour='black'), axis.text.x = element_text(size=14, colour='black'), axis.text.y = element_text(size=14, colour='black')) &gt; ggplot(parastats, aes(x=signalcost, y=choosem)) + geom_point(stat="identity") + geom_errorbar(aes(ymin=chooseselo, ymax=choosesehi), width = 2, size = 1) + labs(x='Signal Cost', y='Choosers (%)') + ylim(0,100)+ theme(plot.background=element_blank(), panel.background=element_blank(), panel.grid.major=element_blank(), panel.grid.minor=element_blank(), axis.line=element_line(colour='black'), axis.title.x=element_text(size=22, colour='black'), axis.title.y = element_text(size=22, colour='black'), axis.text.x = element_text(size=14, colour='black'), axis.text.y = element_text(size=14, colour='black'))