1function [B,opts,stats,start_tic,ok] = spqr_rank_get_inputs (A,method,varargin)
2%SPQR_RANK_GET_INPUTS get the inputs and set the default options.
3% Not user-callable.  Handles the following input syntaxes for functions in
4% the spqr_rank toolbox:
5%
6%   method = 0: spqr_null, spqr_ssi
7%       [ ] = f (A)             % B is [ ], opts empty
8%       [ ] = f (A, [ ])        % B is [ ], opts empty
9%       [ ] = f (A, opts)       % B is [ ]
10%
11%   method = 1: spqr_basic, spqr_cod, spqr_pinv
12%       [ ] = f (A)             % B is [ ], opts empty
13%       [ ] = f (A, [ ])        % B is [ ], opts empty
14%       [ ] = f (A, B)          %           opts empty
15%       [ ] = f (A, B, [ ])     %           opts empty
16%       [ ] = f (A, B, opts)    %
17%       [ ] = f (A, B, tol)     %           opts.tol
18%
19%   method = 2: spqr_ssp
20%       [ ] = f (A)             % N is [ ], k is 1, opts empty
21%       [ ] = f (A, [ ])        % N is [ ], k is 1, opts empty
22%       [ ] = f (A, k)          % N is [ ],         opts empty
23%       [ ] = f (A, N)          %           k is 1, opts empty
24%       [ ] = f (A, N, [ ])     %           k is 1, opts empty
25%       [ ] = f (A, N, opts)    %           k is 1
26%       [ ] = f (A, N, k)       %                   opts empty
27%       [ ] = f (A, N, k, opts) %
28%
29%   method = 3: spqr_rank_opts, return opts for spqr_basic
30%       [ ] = f (A, opts)       % B is [ ]
31%
32% The return values of this function are, in order:
33%
34%       B           the right-hand side, or N for spqr_ssp.  B = [ ] if not
35%                   present.
36%       opts        the opts struct (see below)
37%       stats       a struct (stats.flag, and optionally stats.time_normest)
38%       start_tic   empty, or the beginning tic if opts.get_vals > 1
39%       ok          true if successful, false if inputs are invalid
40%
41% The opts struct is populated with default values, if not present on input.
42%
43% Note that the defaults are different for spqr_ssp than for the other
44% functions.
45
46% Copyright 2012, Leslie Foster and Timothy A. Davis
47
48B = [ ] ;
49opts = struct ;
50stats = struct ;
51start_tic = [ ] ;
52ok = 1 ;
53
54args = nargin - 1 ;     % # of input arguments to spqr_function
55
56if (args == 1)
57
58    % usage: [ ] = spqr_function (A)
59
60elseif (args == 2)
61
62    lastarg = varargin {1} ;
63    is_null_basis_struct = ...
64        isstruct(lastarg) && isfield(lastarg,'Q') && isfield(lastarg,'X') ;
65    if ( isstruct(lastarg) && ~is_null_basis_struct )
66        % usage: [ ] = spqr_function (A, opts)
67        opts = lastarg;
68        % since lastarg is a structure but not an implicit null space basis
69    elseif (isempty (lastarg))
70        % usage: [ ] = spqr_function (A, [ ])
71    elseif (isreal (lastarg) && length (lastarg) == 1)
72        % usage: [ ] = spqr_function (A, k)
73        opts.k = round (lastarg) ;
74    else
75        % usage: [ ] = spqr_function (A, B)
76        B = lastarg ;
77    end
78
79elseif (args == 3 && (method == 1 || method == 2))
80
81    B = varargin {1} ;
82    lastarg = varargin {2} ;
83    if (isstruct (lastarg))
84        % usage: [ ] = spqr_function (A, B, opts)
85        opts = lastarg ;
86    elseif (isempty (lastarg))
87        % usage: [ ] = spqr_function (A, B, [ ])
88    elseif (isreal (lastarg) && length (lastarg) == 1)
89        if (method == 1)
90            % usage: [ ] = spqr_function (A, B, tol)
91            opts.tol = lastarg ;
92        else
93            % usage: [ ] = spqr_function (A, B, k)
94            opts.k = round (lastarg) ;
95        end
96    else
97        % invalid usage: last argument invalid
98        ok = 0 ;
99    end
100
101elseif (args == 4 && method == 2)
102
103    % usage: [ ] = spqr_ssp (A, N, k, opts)
104    B = varargin {1} ;
105    opts = varargin {3} ;
106    opts.k = round (varargin {2}) ;
107
108else
109
110    % invalid usage: too few or too many arguments
111    ok = 0 ;
112
113end
114
115%-------------------------------------------------------------------------------
116% check B
117%-------------------------------------------------------------------------------
118
119[m,n] = size (A) ;
120if (method == 1)
121    if (isempty (B))
122        B = zeros (m,0) ;
123    elseif (size (B,1) ~= m)
124        error ('A and B must have the same number of rows') ;
125    end
126end
127
128if ~ok
129    return
130end
131
132%-------------------------------------------------------------------------------
133% options for all functions
134%-------------------------------------------------------------------------------
135
136if ~isfield (opts, 'get_details')
137    % 0: basic statistics (the default)
138    % 1: detailed statistics:  basic stats, plus input options, time taken by
139    %   various phases, statistics from spqr and spqr_rank subfunctions called,
140    %   and other details.  Normally of interest only to the developers.
141    % 2: basic statistics and a few additional statistics.  Used internally
142    %    by some routines to pass needed information.
143    opts.get_details = 0 ;
144end
145
146if (opts.get_details == 1)
147    start_tic = tic ;
148end
149
150if ~isfield (opts, 'repeatable')
151    % by default, results are repeatable
152    opts.repeatable = 1 ;
153end
154
155% spqr_pinv uses all opts
156
157%-------------------------------------------------------------------------------
158% options for spqr_basic, spqr_cod, and spqr_ssi
159%-------------------------------------------------------------------------------
160
161if (~isfield (opts, 'tol'))
162    % a negative number means the default tolerance should be computed
163    opts.tol = 'default' ;
164end
165
166if (~isfield (opts, 'tol_norm_type'))
167    % 1: use norm (A,1) to compute the default tol
168    % 2: use normest (A, 0.01).  This is the default.
169    opts.tol_norm_type = 2 ;
170end
171
172if (method < 2 && tol_is_default (opts.tol))
173    % compute the default tolerance, but not for spqr_ssp, which doesn't need it
174    if (opts.tol_norm_type == 1)
175        normest_A = norm (A,1) ;
176    else
177        % this is the default
178        normest_A = normest(A,0.01);
179    end
180    opts.tol = max(m,n)*eps(normest_A) ;
181end
182
183if (~isfield (opts, 'nsvals_large'))
184    % default number of large singular values to estimate
185    opts.nsvals_large = 1 ;
186end
187
188%-------------------------------------------------------------------------------
189% options for spqr_basic, spqr_null, spqr_cod, and spqr
190%-------------------------------------------------------------------------------
191
192if (~isfield (opts, 'nsvals_small'))
193    % default number of small singular values to estimate
194    opts.nsvals_small = 1 ;
195end
196
197if (~isfield (opts, 'implicit_null_space_basis'))
198    opts.implicit_null_space_basis = 1 ;
199end
200
201%-------------------------------------------------------------------------------
202% options for spqr_cod (only)
203%-------------------------------------------------------------------------------
204
205if (~isfield (opts, 'start_with_A_transpose'))
206    opts.start_with_A_transpose = 0 ;
207end
208
209%-------------------------------------------------------------------------------
210% options for spqr_ssi (called by spqr_basic, spqr_null, spqr_cod and spqr_pinv)
211%-------------------------------------------------------------------------------
212
213if (~isfield (opts, 'ssi_tol'))
214    opts.ssi_tol = 'default' ;
215end
216
217if (method < 2 && tol_is_default (opts.ssi_tol))
218    % default tolerance for spqr_ssi is the same as spqr_basic, spqr_cod,
219    % spqr_pinv
220    opts.ssi_tol = opts.tol ;
221end
222
223if (~isfield (opts, 'ssi_min_block'))
224    opts.ssi_min_block = 3 ;
225end
226
227if (~isfield (opts, 'ssi_max_block'))
228    opts.ssi_max_block = 10 ;
229end
230
231if (~isfield (opts, 'ssi_min_iters'))
232    opts.ssi_min_iters = 3 ;
233end
234
235if (~isfield (opts, 'ssi_max_iters'))
236    opts.ssi_max_iters = 100 ;
237end
238
239if (~isfield (opts, 'ssi_nblock_increment'))
240    opts.ssi_nblock_increment = 5 ;
241end
242
243if (~isfield (opts, 'ssi_convergence_factor'))
244    opts.ssi_convergence_factor = 0.1 ;     % also 0.25 is often safe
245end
246
247%-------------------------------------------------------------------------------
248% options for spqr_ssi (called by spqr_basic, spqr_null, spqr_cod and spqr_pinv)
249%-------------------------------------------------------------------------------
250
251if (~isfield (opts, 'k'))
252    % number of singular values to compute
253    opts.k = 1 ;
254end
255
256if (~isfield (opts, 'ssp_min_iters'))
257    opts.ssp_min_iters = 4 ;
258end
259
260if (~isfield (opts, 'ssp_max_iters'))
261    opts.ssp_max_iters = 10 ;
262end
263
264if (~isfield (opts, 'ssp_convergence_factor'))
265    opts.ssp_convergence_factor = 0.1 ;
266end
267
268%-------------------------------------------------------------------------------
269% initialize stats
270%-------------------------------------------------------------------------------
271
272% initialize the order of stats, as much as possible
273stats.flag = -1 ;       % -1 means 'not yet computed'
274if method <= 1
275   stats.rank = -1 ;   % -1 means not computed
276end
277if method == 0
278    if ( opts.get_details == 1 && exist('normest_A','var')  )
279        stats.normest_A = normest_A;
280    end
281end
282% for spqr_null and spqr_ssi (method = 0) additional fields initialized
283%      in spqr_null or spqr_ssi
284if method == 1
285    % spqr_basic, spqr_cod, spqr_pinv, initialize stats fields in common to all
286    if opts.get_details == 2 ;
287        stats.rank_spqr = -1 ;
288    end
289    stats.tol = opts.tol ;
290    if ( opts.get_details == 1 && exist('normest_A','var')  )
291        stats.normest_A = normest_A;
292    end
293    stats.tol_alt = -1 ;   % removed later if remains -1
294    stats.est_sval_upper_bounds = -1 ;
295    stats.est_sval_lower_bounds = -1 ;
296    stats.sval_numbers_for_bounds = -1 ;
297    % for spqr_basic, spqr_cod and spqr_pinv additional fields initialized
298    %     in spqr_basic, spqr_cod or spqr_ssi
299end
300if method == 2
301    % for spqr_ssp initialize order for all stats fields
302    stats.est_svals = -1 ;   % -1 means not yet computed
303    stats.est_error_bounds = -1 ;
304    stats.sval_numbers_for_bounds = -1 ;
305    if (opts.get_details == 1)
306        stats.iters = 0 ;
307        stats.opts_used = opts ;
308        stats.time = 0 ;
309        stats.time_initialize = 0 ;
310        stats.time_iters = 0 ;
311        stats.time_est_error_bounds = 0 ;
312        stats.time_svd = 0 ;
313    end
314end
315
316%-------------------------------------------------------------------------------
317% return timings
318%-------------------------------------------------------------------------------
319
320if (opts.get_details == 1)
321    % get the total time to initializations including to computing
322    % normest(A,0.01), if called
323    stats.time_initialize = toc (start_tic) ;
324end
325
326