-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathanymatrix.m
More file actions
672 lines (634 loc) · 26.6 KB
/
anymatrix.m
File metadata and controls
672 lines (634 loc) · 26.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
function varargout = anymatrix(varargin)
%ANYMATRIX Interface for accessing the Anymatrix collections.
% ANYMATRIX is a user interface for the Anymatrix matrix collection.
% It provides commands to list matrices, groups and sets, search for
% matrices by properties, and obtain the matrices by their IDs.
%
% The interface comes with built-in groups of matrices, but users can
% develop their own groups and make them available to other users.
%
% The built-in collection contains 7 groups:
%
% contest - the CONTEST test matrix toolbox of random matrices
% from networks.
% core - miscellaneous matrices.
% gallery - matrices from the MATLAB gallery.
% hadamard - a large collection of (complex) Hadamard matrices.
% matlab - other MATLAB matrices (not in gallery).
% nessie - matrices from real-life networks.
% regtools - matrices from regularization problems.
%
% Anymatrix accepts the following commands. All arguments are character
% vectors or strings, except ones defined by the matrix M-files which
% might take various types of arguments.
%
% help anymatrix - display this information.
% ANYMATRIX('all') - return all matrix IDs in the collection.
% ANYMATRIX('contents', group_name) - displays Contents.m of the group
% with a specified name group_name.
% G = ANYMATRIX('groups') - return the available groups.
% M = ANYMATRIX('groups', group_name) - return matrix IDs that belong
% to the group with a specified name group_name.
% ANYMATRIX('groups', group_name, repository) - clone or update
% an anymatrix group stored in the specified repository.
% ANYMATRIX('help', matrix_id) - list the help for a specified
% matrix (anymatrix(matrix_id, 'help') also accepted).
% M = ANYMATRIX('lookfor', pattern) - returns a list of matrix IDs
% whose help comments contain the specified string/char pattern.
% ANYMATRIX('properties') - show the list of recognized properties.
% ANYMATRIX('properties', matrix_id) - list the properties of a
% specified matrix (anymatrix(matrix_id, 'properties') also
% accepted).
% M = ANYMATRIX('properties', properties) - list matrices having
% the specified properties.
% ANYMATRIX('scan') - force a scan of the file system.
% S = ANYMATRIX('sets') - return the available sets.
% [s, mat1, ..., matK] = ANYMATRIX('sets', set_name) - return matrix IDs
% in S and generate matrices in a specified set.
% ANYMATRIX('test') - run tests of all groups, where available.
% ANYMATRIX('test', group_name) - run tests of the specified group, if
% available.
% [out1, ..., outK] = ANYMATRIX(matrix_id, in1, ..., inN) - get the
% matrix with a specified matrix id and parameters (if any) in1 to
% inN. Some matrices supply multiple output arguments.
%
% Shorthand commands with one or more of the starting letters are also
% accepted, for example 'c', 'cont', 'g', 'gr', 'h', 'l', 'p', 'prop',
% 'sc', 'se', 't'.
%
% Anymatrix supports logical queries to search for matrices by
% properties. In the command anymatrix('properties', '[properties]'), the
% list of properties is a single character vector containing properties
% that have to be separated by an "and" or an "or" and can be preceded by
% a "not". Brackets can also be included to specify precedence.
%
% Anymatrix holds the information about the underlying database of
% matrices in the persistent variables that are initialized by scanning
% the data on the first call to any command. To force an update to these
% variables use anymatrix('scan').
%
% Documentation:
% Nicholas J. Higham and Mantas Mikaitis, Anymatrix: An Extendable MATLAB
% Matrix Collection, User's Guide, MIMS EPrint 2021.15, Manchester
% Institute for Mathematical Sciences, The University of Manchester,
% UK, October 2021.
% References and acknowledgments.
%
% The CONTEST toolbox is included with permission from
% Alan Taylor and Desmond J. Higham. CONTEST: A controllable test matrix
% toolbox for MATLAB. ACM Trans. Math. Software, 35(4):26:1-26:17, 2009.
% https://doi.org/10.1145/1462173.1462175
%
% The Hadamard group is reproduced with permission from
% N. J. A. Sloane, A Library of Hadamard Matrices,
% http://neilsloane.com/hadamard/. "Anything free comes with no guarantee".
%
% The NESSIE collection is included with permission from
% https://outreach.mathstat.strath.ac.uk/outreach/nessie/nessie_transport.html
% Alan Taylor and Desmond J. Higham, NESSIE: Network Example Source
% Supporting Innovative Experimentation, in Ernesto Estrada, Maria
% Fox, Desmond J. Higham and Gian-Luca Oppo, eds, Network Science:
% Complexity in Nature and Technology, pp. 85-106, Springer, 2010.
% https://doi.org/10.1007/978-1-84996-396-1_5
%
% The regtools group is included with permission from the
% Regulariation Tools toolbox at https://www.imm.dtu.dk/~pcha/Regutools/
% P. C. Hansen Regularization Tools: A Matlab package for analysis and
% solution of discrete ill-posed problems. Numer. Algorithms 6(1), 1--35
% (1994). https://doi.org/10.1007/BF02149761
% P. C. Hansen: Regularization Tools version 4.0 for Matlab 7.3.
% Numer. Algorithms 46(2), 189--194 (2007).
% https://doi.org/10.1007/s11075-007-9136-9
% Check that MATLAB 2020b or higher is present.
if verLessThan('matlab','9.9')
error('MATLAB 2020b or newer is required.')
end
% List of built-in anymatrix groups.
built_in_groups = {
'contest'
'core'
'gallery'
'hadamard'
'matlab'
'nessie'
'regtools'
};
% Matrix ID pattern
matrix_ID_pat = ...
asManyOfPattern(alphanumericsPattern | characterListPattern("_") | ...
characterListPattern("-")) + ...
'/' + ...
asManyOfPattern(alphanumericsPattern | characterListPattern("_") | ...
characterListPattern("-"));
% Convert inputs to char arrays if supplied as strings.
if (nargin > 0) && isstring(varargin{1})
varargin{1} = convertStringsToChars(varargin{1});
end
if (nargin > 1) && isstring(varargin{2})
varargin{2} = convertStringsToChars(varargin{2});
end
% Flag used for performing the first scan of the file structure.
persistent files_scanned
persistent set_IDs
persistent group_IDs
persistent matrix_IDs
persistent properties
persistent supported_properties
% Get the directory containing the anymatrix.m file.
root_path = fileparts(strcat(mfilename('fullpath'), '.m'));
% Scan the file structure of the collection to obtain matrix, group and
% set IDs, if it hasn't been scanned yet.
if isempty(files_scanned)
% Add anymatrix/sets and anymatrix/testing to the search path.
addpath(strcat(root_path, '/sets'));
addpath(strcat(root_path, '/testing'));
supported_properties = prop_list();
[set_IDs, group_IDs, matrix_IDs, properties] = ...
scan_filesystem();
files_scanned = 1;
disp('Automatic anymatrix scanning done.');
end
if nargin == 0
help('anymatrix.m');
return;
elseif ~ischar(varargin{1})
error('Anymatrix command was not recognized');
end
% Parse the arguments passed to anymatrix.
command = varargin{1};
if (nargin >= 2)
arg = varargin{2};
if ischar(varargin{2}) && any(startsWith({'properties', ...
'groups', 'sets', 'all', 'scan', 'help', 'test', ...
'lookfor', 'contents'}, varargin{2}))
command = varargin{2};
arg = varargin{1};
end
% Allow use of hyphens instead of underscores, but replace here.
if ischar(arg) && ~any(startsWith({'properties', 'lookfor', ...
'sets'}, command))
arg = strrep(arg, '-', '_');
end
end
% Hyphens -> underscores in matrix IDs.
command = strrep(command, '-', '_');
% Capture some common errors in the arguments.
if matches(command, matrix_ID_pat)
if ~ismember(command, matrix_IDs)
error('Specified matrix ID was not found.');
end
elseif ~any(startsWith({'properties', 'groups', ...
'sets', 'all', 'scan', 'help', 'test', 'contents', ...
'lookfor'}, command))
error('Anymatrix command was not recognized.');
elseif (nargin == 1)
if any(startsWith({'lookfor', 'contents'}, command))
error('Please specify one more argument.');
end
elseif nargin == 2
if ~ischar(arg)
error('This anymatrix command requires string arguments.');
elseif startsWith({'help'}, command) || ...
(startsWith('properties', command) && ...
matches(arg, matrix_ID_pat))
if ~ismember(arg, matrix_IDs)
error('Specified matrix ID was not found.');
end
elseif any(startsWith({'groups', 'contents', 'test'}, command))
if ~ismember(arg, group_IDs)
error('The specified group ID was not found.');
end
elseif startsWith('sets', command)
if ~ismember(arg, set_IDs)
error('ID of the specified set was not found.');
end
end
elseif (nargin > 3) || ((nargin == 3) && ...
~startsWith('groups', varargin{1}))
error('Anymatrix command was not recognized (too many inputs).');
end
% Execute the specified command.
if startsWith('all', command)
varargout{1} = matrix_IDs;
elseif startsWith('contents', command)
show_contents(arg);
elseif startsWith('groups', command)
if (nargin == 1)
varargout{1} = group_IDs;
elseif (nargin == 2)
varargout{1} = matrix_IDs(contains(matrix_IDs, ...
strcat(arg, '/')));
else
update_git_group(arg, varargin{3});
end
elseif startsWith('help', command)
if (nargin == 1)
help anymatrix;
else
show_matrix_help(arg);
end
elseif startsWith('lookfor', command)
varargout{1} = lookfor_term(arg);
elseif startsWith('properties', command)
if (nargin == 1)
[~, I] = sort(lower(supported_properties));
varargout{1} = supported_properties(I);
elseif matches(arg, matrix_ID_pat)
[~, I] = sort(lower(properties{strcmp(matrix_IDs, arg)}));
varargout{1} = properties{strcmp(matrix_IDs, arg)}(I);
else
varargout{1} = search_by_properties(arg);
end
elseif startsWith('scan', command)
supported_properties = prop_list();
[set_IDs, group_IDs, matrix_IDs, properties] = scan_filesystem();
disp('Anymatrix scanning done.');
elseif startsWith('sets', command)
if (nargin == 1)
varargout{1} = set_IDs;
else
S = readcell( ...
strcat(root_path, '/sets/', arg, '.txt'), ...
'Delimiter', ':', 'CommentStyle', '%', ...
'Whitespace', ' \n');
varargout{1} = S;
out_ind = 2;
% Generate matrices using parameters specified in the set.
for index = 1:length(S)
if (ismissing(S{index, 2}))
varargout{out_ind} = eval(strcat('generate_matrix(''', ...
S{index, 1}, ''')'));
else
varargout{out_ind} = eval(strcat('generate_matrix(''', ...
S{index, 1}, ''',', num2str(S{index, 2}), ')'));
end
out_ind = out_ind + 1;
end
end
elseif startsWith('test', command)
if (nargin == 1)
for group = group_IDs.'
run_group_tests(group{1});
end
else
run_group_tests(arg);
end
else
[varargout{1:nargout}] = generate_matrix(command, varargin{2:nargin});
end
% Top level function for scanning the files.
function [c, g, m, p] = scan_filesystem()
c = scan_sets();
g = scan_groups();
m = scan_matrices(g);
p = scan_properties(m);
end
% Scan the sets folder and obtain the set IDs.
function IDs = scan_sets()
IDs = {dir(strcat(root_path, '/sets/*.txt')).name};
% Remove '.txt' extensions from the IDs.
for k = 1:length(IDs)
dotloc = find(IDs{k} == '.');
IDs{k} = IDs{k}(1:dotloc(1)-1);
end
IDs = IDs.';
end
% Try to run function setup() if current group has one.
function run_setup_function(group_private_folder)
run_function_if_present(group_private_folder, 'setup');
end
% Try to run function update() if current group has one.
function run_update_function(group_private_folder)
run_function_if_present(group_private_folder, 'update');
end
% Run function if present.
function run_function_if_present(new_folder, function_name)
current_folder = cd(new_folder);
if exist([function_name '.m'], 'file')
fprintf('Running function %s()...', function_name);
feval(function_name);
fprintf('done.\n');
end
cd(current_folder);
end
% Check if a folder in anymatrix root directory is a group folder.
% Group directories have one private/ directory and one file named
% anymatrix_<dir_name>.m where <dir_name> is the directory name.
function out = is_group_dir(directory)
% Check dir is not current or previous directories '.' and '..',
% and check dir has two files additionally to '.' and '..'.
if (any(strcmp(directory, {'.', '..'})) || ...
(length(dir(strcat(root_path, '/', directory)))) ~= 4)
out = false;
else
% Check dir has a 'private' directory and a file
% anymatrix_<dir_name>.
out = ~(isempty(dir(strcat(root_path, '/', directory, ...
'/private/'))) || ...
isempty(dir(strcat(root_path, '/', directory, ...
'/anymatrix_', directory, '.m'))));
end
end
% Scan the root folder and obtain the group IDs.
function IDs = scan_groups()
contents = dir(root_path);
IDs = {};
for k = 1:length(contents)
if contents(k).isdir && is_group_dir(contents(k).name)
IDs{end+1} = contents(k).name;
addpath(strcat(root_path, '/', contents(k).name));
end
end
IDs = IDs.';
end
% Scan the group folders and obtain the matrix IDs.
function IDs = scan_matrices(groups)
IDs = {};
for group = groups.'
path_to_group = [root_path, '/', group{1}, '/private/'];
mfiles = dir([path_to_group, '*.m']);
for mfile = mfiles.'
% Find which .m files are matrix-generating files.
mfile_contents = fileread([path_to_group, mfile.name]);
if (contains(mfile_contents, 'properties = {') || ...
contains(mfile_contents, 'properties= {') || ...
contains(mfile_contents, 'properties ={') || ...
contains(mfile_contents, 'properties={'))
IDs = [IDs; [group{1}, '/', ...
extractBefore(mfile.name, '.m')]];
end
end
% Read matrix IDs that are placed in properties.m files and
% add them if they are not in yet from the M-files.
if (isfile(strcat(path_to_group, 'am_properties.m')))
handle = str2func(strcat('anymatrix_', group{1}));
P = handle('am_properties');
moreIDs = strcat(group{1}, '/', P(:,1));
IDs = [IDs; moreIDs(~ismember(moreIDs, IDs))];
end
end
end
% Search for matrices that have properties, according to a specified
% logical expression, and return their IDs.
function IDs = search_by_properties(expression)
IDs = {};
% Replace 'and', 'or', and 'not' by corresponding MATLAB symbols.
expression = replace(expression, ' and ', ' & ');
expression = replace(expression, ' or ', ' | ');
expression = replace(expression, ' not ', ' ~');
expression = replace(expression, '(not ', '(~');
if startsWith(expression, 'not')
expression = expression(4:length(expression));
expression(1) = '~';
end
% Assume properties are made up letters, can include a hyphen
% or a white space character, and there is no case sensitivity.
pat = (lettersPattern + whitespacePattern + lettersPattern) ...
| (lettersPattern + characterListPattern('-') ...
+ lettersPattern) ...
| lettersPattern;
% Extract properties from the logical expression and replace
% them by function calls to test for membership.
ex_props = extract(expression, pat);
ind = 1;
new_expression = '';
for p = ex_props.'
mod_prop = strcat('ismember(''', ...
strrep(lower(p{1}), '-', ' '), ...
''', strrep(lower(matrix_properties{1}), ''-'', '' ''))');
trunc_exp = expression(ind:end);
% Find where the property is in the expression.
prop_index = strfind(trunc_exp, p{1});
% Take anything before the property and append the modified
% version of the property.
new_expression = strcat(new_expression, ...
trunc_exp(1:prop_index(1)-1), ...
mod_prop);
% Move the index after the property that was replaced.
ind = ind + prop_index(1) + length(p{1}) - 1;
end
new_expression = strcat(new_expression, expression(ind:end));
% Find matrices whose properties satisfy the specified logical
% expression.
k = 0;
for matrix_properties = properties.'
k = k + 1;
% Test if the expression is true for this matrix
% and add it's ID.
if eval(new_expression)
IDs = [IDs; matrix_IDs{k}];
end
end
end
% Fetch the properties of a specified matrix.
function P = get_properties(matrix_ID)
slashloc = find(matrix_ID == '/');
group_name = matrix_ID(1:slashloc-1);
path_to_group = [root_path, '/', group_name, '/private/'];
matrix_name = matrix_ID(slashloc+1:length(matrix_ID));
handle = str2func(strcat('anymatrix_', group_name));
P = {};
% Get properties from the M-file of the matrix.
mfile_path = strcat(path_to_group, matrix_name, '.m');
if isfile(mfile_path)
mfile_contents = fileread(mfile_path);
if (contains(mfile_contents, 'properties = {') || ...
contains(mfile_contents, 'properties= {') || ...
contains(mfile_contents, 'properties ={') || ...
contains(mfile_contents, 'properties={'))
noutputs = nargout(strcat(path_to_group, matrix_name));
temp = {};
[temp{1:noutputs-1},P] = handle(matrix_name);
end
end
% Get other properties from the entry in the properties.m file.
if (isfile(strcat(path_to_group, 'am_properties.m')))
temp = handle('am_properties');
if (ismember(matrix_name, temp(:, 1)))
temp = temp{strcmp(matrix_name, temp(:, 1)), 2};
P = [P, temp(~ismember(temp, P))];
end
end
P = P.';
end
% Get properties of a specified array of matrices in a cell array of
% cell arrays, arranged in the same order as matrix_IDs.
function P = scan_properties(matrix_IDs)
P = {};
for matrix_ID = matrix_IDs.'
current_properties = get_properties(matrix_ID{1});
if size(current_properties, 2) > 1
current_properties = current_properties';
end
P = [P; {current_properties}];
end
% Add property 'built-in' for the built-in matrices.
for i = 1:length(matrix_IDs)
if any(startsWith(matrix_IDs{i}, built_in_groups))
P{i} = [P{i}; 'built-in'];
end
end
% Add parent properties if not specified.
M = prop_map();
I = inv_prop_map();
for i = 1:length(P)
for j = 1:length(I)
% Find properties that can be added due to absence of some
% other properties.
if ~any(ismember(strrep(lower(I{j, 2}),'-', ' '), ...
strrep(lower(P{i}), '-', ' '))) && ...
~ismember(strrep(lower(I{j, 1}), '-', ' '), ...
strrep(lower(P{i}), '-', ' '))
P{i} = [P{i}; I{j, 1}];
end
end
j = 1;
while j <= length(M)
% Find parent properties of any of the properties already
% in the list and add them if they are not in yet.
if any(ismember(strrep(lower(P{i}), '-', ' '), ...
strrep(lower(M{j, 2}), '-', ' '))) && ...
~ismember(strrep(lower(M{j, 1}), '-', ' '), ...
strrep(lower(P{i}), '-', ' '))
P{i} = [P{i}; M{j, 1}];
j=1;
end
j = j+1;
end
end
% Check if all the properties can be recognized.
for i=1:length(matrix_IDs)
for bad_prop = ...
P{i}(~ismember(strrep(lower(P{i}), '-', ' '), ...
strrep(lower(supported_properties), ...
'-', ' ')))
if ~isempty(bad_prop)
warning('Property %s in %s is not recognized.', ...
bad_prop{1}, matrix_IDs{i});
end
end
end
end
% Generate a specified matrix with the given parameters, if any.
function varargout = generate_matrix(matrix_ID, varargin)
slashloc = find(matrix_ID == '/');
group_name = matrix_ID(1:slashloc-1);
matrix_name = matrix_ID(slashloc+1:length(matrix_ID));
handle = str2func(strcat('anymatrix_', group_name));
if (~isempty(varargin))
[varargout{1:max(1,nargout)}] = handle(matrix_name, ...
varargin{1:length(varargin)});
else
[varargout{1:max(1,nargout)}] = handle(matrix_name);
end
end
% Display help info of a specified matrix.
function show_matrix_help(matrix_ID)
slashloc = find(matrix_ID == '/');
group_name = matrix_ID(1:slashloc-1);
matrix_name = matrix_ID(slashloc+1:length(matrix_ID));
if strcmp('gallery', group_name)
help(strcat('private/', matrix_name));
elseif strcmp('matlab', group_name)
help(matrix_name);
else
help(replace(matrix_ID, '/', '/private/'));
end
end
% Look for a pattern inside all matrix help comments in the collection.
function found_IDs = lookfor_term(term)
found_IDs = {};
for ID_cell = matrix_IDs.'
matrix_ID = ID_cell{1};
slashloc = find(matrix_ID == '/');
group_name = matrix_ID(1:slashloc-1);
matrix_name = matrix_ID(slashloc+1:length(matrix_ID));
path_to_mat = [root_path, '/', group_name, '/private/', ...
matrix_name];
if strcmp('gallery', group_name)
H = help(strcat('private/', matrix_name));
elseif strcmp('matlab', group_name)
H = help(matrix_name);
else
H = help(path_to_mat);
end
if contains(H, term, 'IgnoreCase', true)
found_IDs = [found_IDs; matrix_ID];
end
end
end
% Display info in the Contents.m of a specified group.
function show_contents(group_ID)
if isfile(strcat(root_path, '/', group_ID, '/private/Contents.m'))
type(strcat(root_path, '/', group_ID, '/private/Contents.m'))
else
error('No Contents.m exists for that group.')
end
end
% Create or update a specified git group.
function update_git_group(group_ID, repo_ID)
group_folder = strcat(root_path, '/', group_ID, '/');
% If the group does not exist locally, create folders and clone it.
if ~isfolder(group_folder)
if count(repo_ID, '/') > 1 || ...
contains(repo_ID, ':') || contains(repo_ID, '@')
status = system(strcat( ...
"git clone ", """", repo_ID, """ ", ...
"""", group_folder, 'private"'), '-echo');
else
status = system(strcat( ...
'git clone "https://github.com/', repo_ID, ...
".git"" ", """", group_folder, 'private"'), ...
'-echo');
end
% Create a bridge file to the private/ dir of the group.
if isfile(strcat(...
group_folder, 'private/anymatrix_', group_ID, '.m'))
movefile(strcat(...
group_folder, 'private/anymatrix_', group_ID, '.m'),...
strcat(...
group_folder, 'anymatrix_', group_ID, '.m'));
else
fileID = fopen(strcat(group_folder, ...
'anymatrix_', group_ID, '.m'), 'w');
temp = strcat('function varargout = anymatrix_', ...
group_ID, '(matrix_name, varargin)\n', ...
'handle = str2func(matrix_name);\n', ...
'[varargout{1:nargout}]', ...
'= handle(varargin{1:nargin-1});\n end');
fprintf(fileID, temp);
fclose(fileID);
end
if (status == 0)
disp('Anymatrix remote group cloned.');
run_setup_function([group_folder 'private/']);
else
rmdir(group_folder, 's');
end
else % Group exists. Run git pull to update it.
if ~isfolder(strcat(group_folder, 'private/.git'))
error('Specified group is not a git group.');
else
[exit_code, output] = system('git pull', '-echo');
repository_changed = ~strcmp(output,...
['Already up-to-date.', newline]);
if repository_changed
run_update_function([group_folder 'private/']);
end
end
end
% Rescan the anymatrix file system.
[set_IDs, group_IDs, matrix_IDs, properties] = scan_filesystem();
end
% Run a testsuite of a particular group.
function run_group_tests(group_ID)
handle = str2func(strcat('anymatrix_', group_ID));
test_func = 'test_run';
if (isfile(strcat(root_path, '/', group_ID, '/private/', ...
test_func, '.m')))
handle(test_func);
else
fprintf('Group %s does not contain any tests. \n', group_ID);
end
end
end