Hello! I’m implementing an Agent Based Model (axelrod model of dissemination of culture). Every node has an associated vector of “opinions” (`data`

) on different subjects (number of features is `feat`

). Each step two nodes are chosen random (I get a random node and then a random neighbor using the `neighs`

adjacency list which is a vector of vector where `neighs[j]`

is the vector of all neighbors of node `j`

.

The nodes are compared and a vector of Bool which is true when two nodes disagree on a subject is called `disagreements`

and is created with the `compare!`

function. Along with that `feats - count(disagreements)`

is returned which is the number of overlapping opinions.

Two nodes interact if they have at least 1 and not all opinions in common with probability equal to the number of overlapping opinions. The interaction consist of setting equal one of the opinions where they differ.

Every `nodes`

steps all pair of nodes are tested and the number of active links (that is, the links that have at least 1 but not all opinions in common) is returned.

```
function simulate_system!(
data::Vector{Vector{T}},
feats::Int,
maxtime::Int,
storage::Vector{T},
edges::Vector{Tuple{U,U}},
neighs::Vector{Vector{U}},
nodes::Int
) where {T<:Integer,U<:Integer}
disagreements::BitVector = BitVector(undef, feats)
for t in 1:maxtime
if t % nodes == 0
num_active::Int = get_active(data, feats, edges)
setindex!(storage, num_active, div(t, nodes))
if num_active == 0
println("Absorbing state reached in $t")
break
end
end
node_1 = rand(1:nodes)
node_2 = rand(neighs[node_1])
op_1 = data[node_1]
op_2 = data[node_2]
overlaps::Int = compare!(disagreements, op_1, op_2, feats)
if overlaps != feats && overlaps != 0
if rand() < overlaps / feats
interact!(disagreements, op_1, op_2)
end
end
end
end
```

## Here I have all the functions used in the code if you want to test it out

```
function get_overlaps(data_1::Vector{T}, data_2::Vector{T}) where {T<:Integer}
overlaps::Int = 0
for (el_1, el_2) in zip(data_1, data_2)
if el_1 == el_2
overlaps += 1
end
end
return overlaps
end
function get_active(
data::Vector{Vector{T}},
feats::Int,
edges::Vector{Tuple{U,U}}
) where {T<:Integer,U<:Integer}
num_active::Int = 0
for (node_1, node_2) in edges
overlaps::Int = get_overlaps(data[node_1], data[node_2])
if overlaps != 0 && overlaps != feats
num_active += 1
end
end
return num_active
end
function compare!(
diffs::Union{BitVector,Vector{Bool}},
data_1::Vector{T},
data_2::Vector{T},
feats::Int
) where {T<:Integer}
@inbounds @simd for idx in 1:feats
diffs[idx] = data_1[idx] != data_2[idx]
end
return feats - count(diffs)
end
function interact!(
diffs::Union{BitVector,Vector{Bool}},
data_1::Vector{T},
data_2::Vector{T}
) where {T<:Integer}
idx_diff::Vector{Int} = findall(diffs)
to_agree::Int = rand(idx_diff)
data_1[to_agree] = data_2[to_agree]
end
```

Data is initialized as random with a Poisson distribution and a 150x150 grid. These are the parameters I used

```
using Graphs
using Graphs.SimpleGraphs: adj
using Distributions: Poisson
side::UInt32 = 150
graph = grid((side, side), periodic=false)
n_nodes::Int = nv(graph)
edgelist = Vector{Tuple{Int,Int}}(Tuple.(edges(graph)))
adjlist = Vector{Vector{Int}}(adj(graph))
features = 10
traits = 100
time_steps = 1_000 * n_nodes
opinions = [rand(Poisson(traits), features) for _ = 1:n_nodes]
storage_edges::Vector{Int} = zeros(Int, time_steps ÷ n_nodes)
simulate_system!(
opinions,
features,
time_steps,
storage_edges,
edgelist,
adjlist,
n_nodes
)
```

While trying to profile using VS cdoe profiler I get the following:

**35%**in:`overlaps::Int = compare!(disagreements, op_1, op_2, feats)`

**18%**in:`num_active::Int = get_active(data, feats, edges)`

**16%**in:`node_2 = rand(neighs[node_1])`

**14%**in:`interact!(disagreements, op_1, op_2)`

**8%**in:`op_2 = data[node_2]`

The first four seem fine and work as expected, most of the pairs will have none or all opinions in common so I expect the compare! and the choice of the nodes to be the most impactful functions.

I’m more interested in the 8% due to the second call `data[node_2]`

this is weird also because the `op_1 = data[node_1]`

cannot even be measured by the profiler. **Why is calling a view of a vector the second time slower?**

Also if you see anything that could be optimized (especially in the functions) I would be extremely happy because the computation times are very high. Thanks in advance!