1function C = gb_random (varargin)
2%GB_RANDOM uniformly distributed random GraphBLAS matrix.
3% Implements C = GrB.random (...), C = sprand (...), C = sprand (...),
4
5% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6% SPDX-License-Identifier: GPL-3.0-or-later
7
8%---------------------------------------------------------------------------
9% parse inputs
10%---------------------------------------------------------------------------
11
12% defaults
13dist = 'uniform' ;
14type = 'double' ;
15range = [ ] ;
16sym_option = 'unsymmetric' ;
17firstchar = nargin + 1 ;
18
19% look for strings
20for k = 1:nargin
21    arg = varargin {k} ;
22    if (ischar (arg))
23        arg = lower (arg) ;
24        firstchar = min (firstchar, k) ;
25        switch arg
26            case { 'uniform', 'normal' }
27                dist = arg ;
28            case { 'range' }
29                range = varargin {k+1} ;
30                if (isobject (range))
31                    range = range.opaque ;
32                end
33                [rm, rn, type] = gbsize (range) ;
34                if (rm*rn > 2)
35                    error ('range must contain at most 2 entries') ;
36                end
37                range = gbfull (range, type, 0, struct ('kind', 'full')) ;
38            case { 'unsymmetric', 'symmetric', 'hermitian' }
39                sym_option = arg ;
40            otherwise
41                error ('unknown option') ;
42        end
43    end
44end
45
46symmetric = isequal (sym_option, 'symmetric') ;
47hermitian = isequal (sym_option, 'hermitian') ;
48desc.base = 'zero-based' ;
49
50%---------------------------------------------------------------------------
51% construct the pattern
52%---------------------------------------------------------------------------
53
54if (firstchar == 2)
55
56    % C = GrB.random (A, ...) ;
57    A = varargin {1} ;
58    if (isobject (A))
59        A = A.opaque ;
60    end
61    [m, n] = gbsize (A) ;
62    if ((symmetric || hermitian) && (m ~= n))
63        error ('input matrix must be square') ;
64    end
65    [I, J] = gbextracttuples (A, desc) ;
66    e = length (I) ;
67
68elseif (firstchar == (4 - (symmetric || hermitian)))
69
70    % C = GrB.random (m, n, d, ...)
71    % C = GrB.random (n, d, ... 'symmetric')
72    % C = GrB.random (n, d, ... 'hermitian')
73    m = gb_get_scalar (varargin {1}) ;
74    if (symmetric || hermitian)
75        n = m ;
76        d = gb_get_scalar (varargin {2}) ;
77    else
78        n = gb_get_scalar (varargin {2}) ;
79        d = gb_get_scalar (varargin {3}) ;
80    end
81    if (isinf (d))
82        % construct a full random matrix
83        e = m * n ;
84        I = repmat ((int64 (0) : int64 (m-1)), 1, n) ;
85        J = repmat ((int64 (0) : int64 (n-1)), m, 1) ;
86    else
87        % construct a sparse random matrix with about e entries
88        e = round (m * n * d) ;
89        I = int64 (floor (rand (e, 1) * m)) ;
90        J = int64 (floor (rand (e, 1) * n)) ;
91    end
92
93else
94
95    error ('invalid usage') ;
96
97end
98
99%---------------------------------------------------------------------------
100% construct the values
101%---------------------------------------------------------------------------
102
103if (isequal (type, 'logical'))
104
105    % X is logical: just pass a single logical 'true' to GrB.build
106    X = true ;
107
108else
109
110    % construct the initial random values
111    if (isequal (dist, 'uniform'))
112        X = rand (e, 1) ;
113    else
114        X = randn (e, 1) ;
115    end
116
117    % scale the values and typecast if requested
118    if (~isempty (range))
119        lo = double (min (range)) ;
120        hi = double (max (range)) ;
121        if (contains (type, 'int'))
122            % X is signed or unsigned integer
123            X = cast (floor ((hi - lo + 1) * X + lo), type) ;
124        elseif (~contains (type, 'complex'))
125            % X is single or double real
126            X = cast ((hi - lo) * X + lo, type) ;
127        else
128            % X is complex: construct random imaginary values
129            if (isequal (dist, 'uniform'))
130                Y = rand (e, 1) ;
131            else
132                Y = randn (e, 1) ;
133            end
134            X = (hi - lo) * X + lo ;
135            Y = (hi - lo) * Y + lo ;
136            if (isequal (type, 'single complex'))
137                % X is single complex
138                X = single (X) ;
139                Y = single (Y) ;
140            end
141            X = complex (X, Y) ;
142        end
143    end
144
145end
146
147%---------------------------------------------------------------------------
148% build the matrix
149%---------------------------------------------------------------------------
150
151C = gbbuild (I, J, X, m, n, '2nd', desc) ;
152
153% make it symmetric or hermitian, if requested
154L = gbselect ('tril', C, -1) ;
155if (symmetric)
156    % C = tril (C) + tril (C,-1)'
157    C = gbeadd (gbselect ('tril', C, 0), '+', gbtrans (L)) ;
158elseif (hermitian)
159    % C = L + L' + real (diag (C))
160    LT = gbtrans (L) ;
161    if (contains (gbtype (LT), 'complex'))
162        LT = gbapply ('conj', LT) ;
163    end
164    D = gbselect ('diag', C, 0) ;
165    if (contains (gbtype (D), 'complex'))
166        D = gbapply ('creal', D) ;
167    end
168    C = gbeadd (L, '+', gbeadd (LT, '+', D)) ;
169end
170
171