//
```// EVOGOD
// SciLab program to simulate the evolution of religion
// Version:              1.0
// Modification date:    1/28/2008
// Copyright 2008 James W. Dow
// This program is released under the GNU General Public License Version 2, June 1991. See http://www.gnu.org/licenses/gpl.txt

// SYSTEM PARAMETERS

ns = 140; ip1 = 10; le = 65; mc = 5; dcr = 0.01; dcu = 0.01; dcur = 0.01; dfir = 0.010; dfiu = -0.005; dfisu = -0.02; dp = 0; lr = 0; ur = 1; lv = 0;  uu = 1; dist = 0; popgrow = 0; greenbeard = 1; mult =1; cmr = 0.5; cmu = 0.5; icp = 0.2;

// MODEL

// Build the initial population matrix (a) of agents . We don't know the size yet. It is easier to build it and then compute the size. Each agent is a row.
nva = 6;  //  Number of variables (columns) for each agent vector
// The column variables for each agent are
// 1. age (ag)
// 2. initial probability of communicating a real experiences (ipr). A real experience is an experience that gives the holder knowledge that can enhance the fitness of others. This knowledge can be communicated.
// 3. initial probability of communicating unreal experiences (ipu)  A number representing the probability that the agent will personally have an unreal experience. An unreal experience is something that can be communicated but contains no knowledge that can enhance fitness. The probability variables pr and pu represent biological evolution in the brain.
// 4. developing probability of communicating a real experience (cpr). This changes during the simulation
// 5. developing probability of communicating an unreal experience (cpu).
// 6.fitness (fi) The number of offspring produced over a lifetime.

// INITIALIZATION of ages and number of agents
// The number of agents in cohort k is ip1 - (k-1)*dp.
// Function for the number of agents in cohort k
function y = na(k), y = ip1 - (k-1) * dp, endfunction;

// Set up ages
// i indexes the cohort, j indexes the column of the a matrix.
// Do the first cohort. a(1) contains the age. The maximum number of cohorts is le, the initial life expectancy. However there are ilkley to be fewer if the population in each cohort decrements (dp) by a large amount
a = ones(na(1),nva);
// Do remaining cohorts
for i = 2:le;
if na(i) < 0 then break; end;
b = ones(na(i),nva) * i ;
a = cat(1,a,b);
end;

// Determine the size of the population
// Function for the number of rows in a matrix.
function y = sz(x), y=size(x,'r'); endfunction;
// Set initial population size
ips = sz(a);

// INITIAL COMMUNICATION PROBABILITIES
// Set up initial probalities of communicating a real experience, a(:,2) and, an unreal experience, a(:,3).
// Set up a random vector of  probabilities. If dist = 0 use a uniform distribution. If dist = 1 use a binomial distribution.
select dist ;
case 0 then;   // Uniform distribution
// Function to set up a random vector of uniformly distributed probabilities between l and u.
function y = rv(l,u), y = (u - l) * rand(ips,1) + l, endfunction;
a(:,2) = rv(lr,ur);
a(:,3) = rv(lv,uu);
case 1 then;   // Binomial distribution
a(:,2) = grand(ips,1,'bin',ip1,ur) / ip1;
a(:,3) = grand(ips,1,'bin',ip1,uu) / ip1;
end;
a(:,4:5) = ones(ips,2)*icp;
// INITIAL FITNESS
a(:,6) = ones(ips, 1);

// Set up recording for the steps.
rps = ones(ns,1);		// Population size
mcp = zeros(ns,2); // Mean of the probability of commnicating real and unreal information

// STEP THROUGH THE SIMULATION
// Note that in this simulation it is possible for an agent to communicate with himself. This does not seem to be a conceptual problem and occurs in reality.

// Functions to provide a set of x random indices to agents in a. greenbeard determines the distribution from which the random indices are selected.

select greenbeard;

case 0 then ; // The probabilities of selection are distributed uniformly over the population
function y=ria(x), y1=grand(1,'prm',(1:sz(a))'), y=y1(1:x), endfunction;

case 1 then ; // The probabilities of selection are distributed according to the current probabilities, cpu, of generating unreal communications. The higher the cpu of an agent, the greater the chance of it being selected.
function y=ria(x);
ps = size(a,'r')
// Normalize the cpu so that they sum to 1
y1 = a(:,5) / sum(a(:,5))
// Form a cumulative distribution
y2 = cumsum(y1)
y = []    // Initialize y as a blank vector.
for i = 1:x
y3 = y2 < rand() // A T-F vector for lower values
y =[y, sum(y3)+1] // Counts agents lower in the cumulative distribution and adds the count to the vector, thus creating the index of the area within which the random number lies.
end
endfunction;
end;

// START STEPPING
for s = 1:ns;   // Do the step
// Calculate population size for this step
ps = sz(a);
nrc = 0;  // monitor total real communications
nuc = 0;  // monitor unreal communications
for j = 1:ps; // Do the agents

// Communicate REAL experiences
// The number of agents communicated with (nca) will depend on the communnicators probablity of communicating real information. It will be a proportion of mc
nca = round(a(j,4) * mc) ; // Get the number of agents to receive real communications from this one.
// Select a set of agents to receive real communications. Note that i is a vector of indices.
i = ria(nca); // select a subset of agents in a at random. i is a column vector. It can be empty
// Have them learn to communicate real experiences
if ~ (i == []) then;
// Change the probability of the receivers communicating real information. This will depend on the inherited probability of communicating unreal real information
a(i,4) = min(ones(size(i,'r'),1),a(i,4) + a(i,2)*dcr);
if mult == 0 then;
a(i,6) = a(i,6) + (cmr * dfir); // Multiply the amount by a constant, cmr
else; // Multiply by the receivers learned probability of communicating real information a(i,2)
a(i,6) = a(i,6) + (a(i,4) * dfir);
end;
end;

// Communicate UNREAL experiences. The number of agents contacted will depend on the probability of communicating unreal information
nca = a(j,5) * mc ; // Calculate number
nuc = nuc + nca;  // Add to unreal communications
// Select a set of agents randomly
i = ria(nca); // note that i is a vector and possibly null if there are less than .5 agents to contact
// Are there agents to contact
if ~ (i == []) then;
// Change the probability of the receivers communicating unreal information
a(i,5) = min(ones(size(i,'r'),1),a(i,5) + a(i,3)*dcu);
// Change the probability of the receiver's communicating real information
a(i,4) = min(ones(size(i,'r'),1),a(i,4) + a(i,2)*dcur);
//Change the fitness of the receiver. dfiu will normally be negative
if mult == 0 then;
a(i,6) = a(i,6) + (cmu * dfiu); // Multiply by a constant
else;
a(i,6) = a(i,6) + (a(i,5) * dfiu); //Multiply by the recivers learned probability of making unreal communications
end;
end;
// Make the sender pay a cost for sending unreal information. This is the cost of costly signaling, and can occur even if there are no receivers
a(j,6) = a(j,6) + dfisu; // Note dfisu is normally negative
end; // Agents are done. j is free

// EVOLVE THE POPULATION OF AGENTS
a(:,1) = a(:,1) + 1;

//Find agents who will die
for i = 1:sz(a);
if a(i,1) > le then; ida = [ida ; i]; // Add the index to ida
end;
end;
// Calculate the number of offspring of each dead agents
no = round(a(ida,6)); // vector of the number of offspring of agents indexed by ida
// Form new offspring with age 1 and fitness 1 (not inherited)
// Maintain the probabilities of communication of the parents
for i = 1:sz(ida); // Scan dead agents
j = ida(i) ; // index of the dead agent in a
for k=1:no(i); // Scan number of offspring
new = [1, a(j,2), a(j,3), icp, icp, 1];
// Catenate new agent at the end of a
a(\$+1,:) = new;
end;
end;
a(ida,:) = [];     // Remove the dead ones from a.

// POPULATION GROWTH CONTROL
// Function to  randomly select x agents selected from a uniform distribution.

function y=riau(x), y1=grand(1,'prm',(1:sz(a))'), y=y1(1:x), endfunction;

select popgrow ;
case 0 then; // Population can grow or decline. Do nothing
case 1 then;// Control the increase or the decline
dps = sz(a) - ips; // Calculate the change in population size
if dps > 0 then ; // There is an increase in population
// Remove dps agents at random
i = riau(dps); // Get a uniform set at random
a(i,:) = [] ; // Kill them off
elseif dps < 0 then ; // There is a decrease in population
i = riau(-dps) ; // Pick a set of agents at random
// Have them reproduce
// Maintain the probabilities of communication of the parents
new = [ones(-dps,1), a(i,2:3), a(i,2:3), ones(-dps,1)];
// Catenate new agents at the end of a
a = [a ; new];
end; // End if
// There is neither an increase of a decrease
end; // End of population control

// save results for this step

ps = sz(a);    // Calculate population size
rps(s,1) = ps; // Record the population size
mcp(s,:) = [mean(a(:,2)), mean(a(:,3))]; // record means of pr and pu
// immediate display
printf("step %i population %i \tmean pr %f mean pu  %f \n",s,ps,mcp(s,1),mcp(s,2));

end; // Move to next step
// End of simulation

// PLOT RESULTS
xbasc(0);
scf(0);    // Open first plot window.
plot2d(1:ns,rps);	// Population size per step
ax = get("current_axes");
ax.x_label.text = "Step";
ax.x_label.font_size = 3;
ax.y_label.font_size = 3;
ax.sub_ticks = [3,1];
xbasc(1);
scf(1);   // Open second plot window.
plot2d(1:ns,mcp);   // Probability of real and unreal communications per step
ax = get("current_axes");
ax.x_label.text = "Step";
ax.x_label.font_size = 3;
ax.y_label.font_size = 3;
ax.sub_ticks = [3,1];
// Plot histograms of pr and pu
xbasc(2); scf(2);   // Open third plot window
title("Final Distribution of ipr", 'fontsize', 4);
x = nfreq(int(a(:,2)*10));bar (x(:,1),x(:,2))
xbasc(3); scf(3);   // Open fourth plot window
title("Final Distribution of ipu", 'fontsize', 4);
x = nfreq(int(a(:,3)*10));bar (x(:,1),x(:,2));
// ```