What I am trying to do is write some code to generate huge random undirected weighted graphs. I will have a parameter to control sparsity, but it will remain relatively sparse, so I want to generate these in CSR form.
I know about the Erdős-Rényi model to generate random matrices. In that case, however, it seems you are generating an nxn square matrix (it would be square in my case since it's a graph), which you could then subsequently convert to CSR or some other format. However what if you want to generate directly into CSR format, to enable you to get the most out of your memory?
My idea was, instead of independently deciding if each edge exists (as in the ER model, at least the G(n,p) version), you could instead randomly decide how many edges exist at the beginning by rolling number (0, n choose 2) which are the min/max number of possible edges (in my case I would set the upper bound to something like 10% of the maximum). However, having trouble figuring out a way to construct the COL_INDEX and ROW_INDEX vectors in a way that keeps it perfectly random and independent. For COL_INDEX, you could probably just randomly assign a number with equal probability with the number of intended columns. But then for ROW_INDEX I'm not sure what you could do. Maybe use some probability distribution to do a "bins and buckets" thing, but I'm not sure how you could avoid putting entries in the same place, since an edge's identity is determined by both INDEX vectors.
Also, I'm not sure if CSR is really the right form anyway. If there is another compressed row storage that is more apt for random graph generation I would be happy to hear it. Additionally I intend these to be undirected weighted graphs with no loops, so (in regular matrix form) it'd have to be symmetric around the diagonal and have 0s on the diagonal, which could complicate things.
A format like CSR is not useful for working with graphs; even basic queries like "is there an edge between vertex $i$ and vertex $j$?" are not straightforward. Use the data structures provided by the programming language you're using.
For example, you could store an adjacency matrix as a hash table (for example) that maps every adjacent pair $\{i,j\}$ to the weight of edge $ij$. This should only take up space linear in the number of edges, and the best thing of all is you don't have to worry about how that happens.
To generate this randomly, first choose a number of edges $m \sim \text{Binomial}( \binom n2, p)$. When we expect $m \ll n^2$, we should be careful to do this step efficiently, since the naive algorithm of flipping $\binom n2$ coins takes quadratic time. Some algorithms here will work in $O(m)$ time instead, which is better for sparse graphs.
Then, generate the edges one at a time by picking two random endpoints. When generating an edge, you'll want to check that it does not already exist (and try again if it does). However, for sparse random graphs, this should not come up very often.
You can also use adjacency lists, but these are trickier to generate, since we can't ask "is there an edge $ij$" as quickly.
If you want to save these graphs, but your code is still going to be the only thing working with them, then - again - do the thing your programming language provides to export your object as a file. Messing around with file formats is only important if you want other people to work with your graphs.
If you do, well - if you need a specific program to understand your graphs, check what that program is using. If not, for just unweighted graphs I'd consider graph6 and sparse6 formats, but I don't know anything standard for weighted graphs.
Finally, at this point, you could look into exporting your graph into a CSR or other sparse matrix form. The easiest thing to code would be the coordinate list version, where you'd just go through all your edges one at a time and export them.