The Brim package offers a (currently limited) way to do significance testing using permutations with null models. Events during the permutation process are logged every two minutes.

For example, the following lines will first measure modularity on the original data, then measure modularity on a permutation of A with the same number of ones.

A = map((x) -> x<0.2?1:0, rand(50, 100))
A |> partition_lp |> recursive_brim! |> Q
A |> null_preserve_marginals |> partition_lp |> recursive_brim! |> Q

Because swap algorithms need to look for swapable submatrices, they can take a while to run.

The null_preserve_rows_marginals function does the same routine but only enforces the equality of rows marginals (same thing for s/row/column/). It may take longer to run because this routine introduces the possibility of emptying rows or columns, in which case the swapping step is not valid.

A final null model (null_preserve_fill) only conserves the matrix fill: the number of arcs are kept, but not the marginals.

Example:

A = map((x) -> x<0.2?1:0, rand(80, 90))
n_samples = 50
empirical_q = A |> partition_lp |> recursive_brim! |> Q
# The next line would benefit from being run using pmap
shuffled_q = map((x) -> A |> null_preserve_marginals |> partition_lp |> recursive_brim! |> Q, 1:n_samples)
# (APPROXIMATION of the p-value for the hypothesis that empirical_Q > random_Q)
pvalue = sum(empirical_q .<= shuffled_q) / n_samples