library(imaginarycss)2026-02-26
The imaginarycss package provides tools for analyzing Cognitive Social Structures (CSS), focusing on the discrepancies between actual social networks and individuals’ perceptions of those networks. The package implements the methods described in Tanaka and Vega Yon (2023), “Imaginary Structures as Evidence of Social Cognition” (doi: 10.1016/j.socnet.2023.11.005).
Cognitive Social Structures (CSS) represent how individuals perceive the entire social network around them. While traditional network analysis asks “Who is connected to whom?”, CSS analysis asks “Who thinks who is connected to whom?”
When we compare these perceptions to the actual network structure, we can identify various types of perceptual errors, including:
These errors are not random—they reveal systematic cognitive biases in how people understand social structure.
library(imaginarycss)The fundamental data structure in imaginarycss is the barry_graph object. It stores a collection of networks: the first is the “true” (baseline) network and subsequent layers represent each perceiver’s view of the network.
The most straightforward way to create a barry_graph is from a list of adjacency matrices. The first matrix is the true network; the rest are individual perceptions.
# True network (4 nodes)
true_net <- matrix(c(
0, 1, 0, 1,
1, 0, 1, 0,
0, 1, 0, 1,
1, 0, 1, 0
), nrow = 4, byrow = TRUE)
# Person 1 over-perceives ties (false positives)
perceived_net1 <- matrix(c(
0, 1, 1, 1,
1, 0, 1, 0,
1, 1, 0, 1,
1, 0, 1, 0
), nrow = 4, byrow = TRUE)
# Person 2 under-perceives ties (false negatives)
perceived_net2 <- matrix(c(
0, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 1,
0, 0, 1, 0
), nrow = 4, byrow = TRUE)
graph <- new_barry_graph(list(true_net, perceived_net1, perceived_net2))
print(graph)A barry_graph with 3 networks of size 4
. . 1.00 . 1.00
1.00 . 1.00 .
. 1.00 . 1.00
1.00 . 1.00 .
Skipping 8 rows. Skipping 8 columns.
Alternatively, you can pass a single block-diagonal matrix where each n x n block corresponds to a network layer.
# Build an 8x8 block-diagonal matrix (two 4x4 networks)
source_ <- c(1, 2, 3, 1)
target_ <- c(2, 1, 4, 4)
source_ <- c(source_, source_[-1] + 4)
target_ <- c(target_, target_[-1] + 4)
adjmat <- matrix(0L, nrow = 8, ncol = 8)
adjmat[cbind(source_, target_)] <- 1L
graph2 <- new_barry_graph(adjmat, n = 4)
print(graph2)A barry_graph with 2 networks of size 4
. . 1.00 . 1.00
1.00 . . .
. . . 1.00
. . . .
Skipping 4 rows. Skipping 4 columns.
Once a barry_graph is created, you can inspect its attributes and extract an edge list. The netsize attribute gives the number of nodes per layer, and endpoints marks the boundary indices of each layer in the underlying block-diagonal structure.
# Network size and layer boundaries
data.frame(
Attribute = c("Network size", "Endpoints"),
Value = c(attr(graph, "netsize"),
paste(attr(graph, "endpoints"), collapse = ", "))
)
## Attribute Value
## 1 Network size 4
## 2 Endpoints 8, 12
# First rows of the edge list
head(barray_to_edgelist(graph))
## source target
## [1,] 1 2
## [2,] 1 4
## [3,] 2 1
## [4,] 2 3
## [5,] 3 2
## [6,] 3 4