From c21cd3f37aa2ca3a9127939f036317bb3b6f3cc6 Mon Sep 17 00:00:00 2001 From: Michael Innerberger <michael.innerberger@asc.tuwien.ac.at> Date: Wed, 9 Aug 2023 16:38:45 -0400 Subject: [PATCH] Clean up LevelDataCollection --- .../LevelDataCollection.m | 71 ++++++++----------- lib/storage/@LevelDataCollection/get.m | 31 ++++---- .../@LevelDataCollection/plotStatistics.m | 27 ++++--- .../@LevelDataCollection/printHeader.m | 5 +- lib/storage/@LevelDataCollection/printItem.m | 12 ++-- .../@LevelDataCollection/printStatistics.m | 28 ++++---- lib/storage/@LevelDataCollection/printTable.m | 6 +- lib/storage/@LevelDataCollection/saveToFile.m | 11 ++- .../@LevelDataCollection/saveToTable.m | 11 ++- lib/storage/@LevelDataCollection/set.m | 18 +++-- lib/storage/TimeIt.m | 21 +++--- 11 files changed, 122 insertions(+), 119 deletions(-) diff --git a/lib/storage/@LevelDataCollection/LevelDataCollection.m b/lib/storage/@LevelDataCollection/LevelDataCollection.m index 623d50f..6cc2e4f 100644 --- a/lib/storage/@LevelDataCollection/LevelDataCollection.m +++ b/lib/storage/@LevelDataCollection/LevelDataCollection.m @@ -41,13 +41,6 @@ classdef LevelDataCollection < handle isInitialRun (1,1) boolean end - properties (Dependent, Access=private) - % String specifying output format in printItem - formatSpecifier (1,:) char - % String specifying header format in prinItem - headerSpecifier (1,:) char - end - properties (Access=protected) % Separator for printing to command line separator @@ -66,8 +59,6 @@ classdef LevelDataCollection < handle end ensureFolderExists(obj.root); - % TODO: set output of hostname to string and remove cast - % TODO: does it make sense to store this here? -> see e.g. get.problem before obj.metaData = dictionary(... "problem", "problem", ... "domain", "domain", ... @@ -115,37 +106,26 @@ classdef LevelDataCollection < handle file = obj.metaData("identifier") + '_collection'; end - function spec = get.headerSpecifier(obj) - % Creates formatting string for the header of the output - % to command line - spec = [' run', obj.separator]; + function spec = getHeaderSpecifier(obj, separator) + % Creates formatting string for the header of the output to command line + spec = cell(1, obj.nTimeVariable+1); + spec{1} = ' run'; for j = 1:obj.nTimeVariable t = obj.item{1}.type(obj.timeVariable{j}); - if j < obj.nTimeVariable - spec = [spec, '%', obj.getWidth(t), 's', obj.separator]; %#ok<*AGROW> - else - spec = [spec, '%', obj.getWidth(t), 's\n']; - end - end - if obj.nTimeVariable == 0 - spec = [spec, '\n']; + spec{j+1} = assembleSpecifier(obj.getWidth(t), 's'); end + spec = strjoin(spec, separator) + "\n"; end - function spec = get.formatSpecifier(obj) + function spec = getFormatSpecifier(obj, separator) % Creates formatting string for printing to command line - spec = ['%4d', obj.separator]; + spec = cell(1, obj.nTimeVariable+1); + spec{1} = '%4d'; for j = 1:obj.nTimeVariable t = obj.item{1}.type(obj.timeVariable{j}); - if j < obj.nTimeVariable - spec = [spec, '%', obj.getWidth(t), t.formatSpec, obj.separator]; - else - spec = [spec, '%', obj.getWidth(t), t.formatSpec, '\n']; - end - end - if obj.nTimeVariable == 0 - spec = [spec, '\n']; + spec{j+1} = assembleSpecifier(obj.getWidth(t), t.formatSpec); end + spec = strjoin(spec, separator) + "\n"; end %% READ ITEM DATA @@ -154,14 +134,21 @@ classdef LevelDataCollection < handle %% MODIFY ITEMS set(obj, jItem, varargin) - function append(obj, varargin) - %%APPEND simplified addition specified data to this list, the - %cell array varargin must contain LevelData objects - % APPEND(obj, varargin) - assert(all(isa(varargin{:}, 'LevelData')), ... - 'Arguments must be of class LevelData'); - indices = obj.nItem + (1:length(varargin)); - obj.set(indices, varargin{:}); + function append(obj, data) + %%APPEND simplified addition specified of data to this list, one or + %more LevelData objects + % APPEND(obj, data) + + arguments + obj + end + + arguments (Repeating) + data LevelData + end + + indices = obj.nItem + (1:length(data)); + obj.set(indices, data{:}); end function remove(obj, indices) @@ -187,6 +174,10 @@ classdef LevelDataCollection < handle width = num2str(max(type.printWidth, obj.minimalWidth)); end - printTable(obj, fid, variableName, data) + printTable(obj, fid, variableName, data, separator) end end + +function spec = assembleSpecifier(width, format) + spec = ['%', num2str(width), format]; +end \ No newline at end of file diff --git a/lib/storage/@LevelDataCollection/get.m b/lib/storage/@LevelDataCollection/get.m index 57e2446..025502e 100644 --- a/lib/storage/@LevelDataCollection/get.m +++ b/lib/storage/@LevelDataCollection/get.m @@ -1,9 +1,9 @@ -function output = get(obj, jItem, varargin) +function output = get(obj, jItem, variableName) %%GET extracts data from this LevelDataCollection object for a given list -%jItem of item numbers, the cell array varargin must contain the names of -%the variables to return -% output = GET(obj, jItem, varargin) -% output = GET(obj, ':', varargin) +%jItem of item numbers. One or more variables to be returned can be specified by +%their names. +% output = GET(obj, jItem, variableName, ...) +% output = GET(obj, ':', variableName, ...) % Copyright 2023 Philipp Bringmann % @@ -21,30 +21,37 @@ function output = get(obj, jItem, varargin) % along with this program. If not, see <http://www.gnu.org/licenses/>. % + arguments + obj + jItem {mustBeIndexVector} = ':' + end + + arguments (Repeating) + variableName {mustBeTextScalar} + end - % Proceed input if strcmp(jItem, ':') jItem = 1:obj.nItem; end % Initialise output variable - output = cell(1, length(varargin)); + output = cell(1, length(variableName)); % Determine number of levels (uses first item!) nLevel = obj.item{1}.nLevel; % Iterate over variables - for jVariable = 1:length(varargin) - variableName = varargin{jVariable}; + for jVariable = 1:length(variableName) + name = variableName{jVariable}; % Check for presence of variable - if ~ismember(variableName, obj.timeVariable) - warning(['Variable ', variableName, ' not found']); + if ~ismember(name, obj.timeVariable) + warning(['Variable ', name, ' not found']); data = []; else data = zeros(nLevel, length(jItem)); % Iterate over items for k = 1:length(jItem) - data(:,k) = obj.item{jItem(k)}.get(':', variableName); + data(:,k) = obj.item{jItem(k)}.get(':', name); end end % Store to return variable diff --git a/lib/storage/@LevelDataCollection/plotStatistics.m b/lib/storage/@LevelDataCollection/plotStatistics.m index 20ce372..3c81e35 100644 --- a/lib/storage/@LevelDataCollection/plotStatistics.m +++ b/lib/storage/@LevelDataCollection/plotStatistics.m @@ -1,8 +1,8 @@ -function ax = plotStatistics(obj, xVariable, varargin) +function ax = plotStatistics(obj, xVariable, yVariable) %%PLOTSTATISTICS plots with statistical information (mean value with min -%and max value) of scalar time variables (specified in varargin) with +%and max value) of scalar time variables (specified in yVariable) with %respect to the variable xVariable, returns handle to axis object -% PLOTSTATISTICS(obj, xVariable, varargin) +% PLOTSTATISTICS(obj, xVariable, yVariable, ...) % Copyright 2023 Philipp Bringmann % @@ -20,25 +20,30 @@ function ax = plotStatistics(obj, xVariable, varargin) % along with this program. If not, see <http://www.gnu.org/licenses/>. % + arguments + obj + xVariable {mustBeTextScalar} + end + + arguments (Repeating) + yVariable + end % Choose time variables for plotting - if nargin < 3 - varargin = obj.timeVariable; + if isempty(yVariable) + yVariable = obj.timeVariable; else - varargin = intersect(varargin, obj.timeVariable); + yVariable = intersect(yVariable, obj.timeVariable); end - % Specify separator for table - obj.separator = ' '; - % Extract data for x-axis xData = obj.item{1}.get(':', xVariable); % Extract data from each item and on each level - data = obj.get(':', varargin{:}); + data = obj.get(':', yVariable{:}); % Create plot - ax = plotData(xData, varargin, data); + ax = plotData(xData, yVariable, data); % Add title title(ax, 'Runtime plot'); diff --git a/lib/storage/@LevelDataCollection/printHeader.m b/lib/storage/@LevelDataCollection/printHeader.m index 4dadef4..b3225a5 100644 --- a/lib/storage/@LevelDataCollection/printHeader.m +++ b/lib/storage/@LevelDataCollection/printHeader.m @@ -21,11 +21,8 @@ function printHeader(obj) % - % Set separator variable - obj.separator = ' '; - % Create header with variable names - header = sprintf(obj.headerSpecifier, obj.timeVariable{:}); + header = sprintf(obj.getHeaderSpecifier(' '), obj.timeVariable{:}); % Print header to command line fprintf(header); diff --git a/lib/storage/@LevelDataCollection/printItem.m b/lib/storage/@LevelDataCollection/printItem.m index 8238c19..b83bfd2 100644 --- a/lib/storage/@LevelDataCollection/printItem.m +++ b/lib/storage/@LevelDataCollection/printItem.m @@ -22,10 +22,9 @@ function printItem(obj, jItem) % along with this program. If not, see <http://www.gnu.org/licenses/>. % - - % Print final item by default - if nargin < 2 - jItem = obj.nItem; + arguments + obj + jItem = obj.nItem end % Print header in case of plotting the first level @@ -33,9 +32,6 @@ function printItem(obj, jItem) obj.printHeader(); end - % Set separator variable - obj.separator = ' '; - % Iterate over given list of item indices for k = 1:length(jItem) % Extract data of all time variables @@ -47,6 +43,6 @@ function printItem(obj, jItem) data{ind} = obj.item{jItem(k)}.level.(obj.timeVariable{l}); end % Print information on current item to command line - fprintf(obj.formatSpecifier, data{1:ind}); + fprintf(obj.getFormatSpecifier(' '), data{1:ind}); end end \ No newline at end of file diff --git a/lib/storage/@LevelDataCollection/printStatistics.m b/lib/storage/@LevelDataCollection/printStatistics.m index 6bc8cad..1c9766a 100644 --- a/lib/storage/@LevelDataCollection/printStatistics.m +++ b/lib/storage/@LevelDataCollection/printStatistics.m @@ -1,7 +1,7 @@ -function printStatistics(obj, varargin) +function printStatistics(obj, variable) %%PRINTSTATISTICS prints statististical information of scalar time -%variables (specified in varargin) -% PRINTSTATISTICS(obj, varargin) +%variables (specified in variable) +% PRINTSTATISTICS(obj, variable, ...) % Copyright 2023 Philipp Bringmann % @@ -19,26 +19,30 @@ function printStatistics(obj, varargin) % along with this program. If not, see <http://www.gnu.org/licenses/>. % + arguments + obj + end + + arguments (Repeating) + variable {mustBeTextScalar} + end % Choose time variables for plotting - if nargin < 2 - varargin = obj.timeVariable; + if isempty(variable) + variable = obj.timeVariable; else - varargin = intersect(varargin, obj.timeVariable); + variable = intersect(variable, obj.timeVariable); end - % Specify separator for table - obj.separator = ' '; - % Extract data from each item and on each level - data = obj.get(':', varargin{:}); + data = obj.get(':', variable{:}); % Print separator between tables fprintf('\n'); % Print table for each given variable - for j = 1:length(varargin) - obj.printTable(1, varargin{j}, data{j}); + for j = 1:length(variable) + obj.printTable(1, variable{j}, data{j}, ' '); fprintf('\n\n'); end end diff --git a/lib/storage/@LevelDataCollection/printTable.m b/lib/storage/@LevelDataCollection/printTable.m index 647fb2c..7756663 100644 --- a/lib/storage/@LevelDataCollection/printTable.m +++ b/lib/storage/@LevelDataCollection/printTable.m @@ -1,4 +1,4 @@ -function printTable(obj, fid, variableName, data) +function printTable(obj, fid, variableName, data, separator) %%PRINTTABLE auxiliary private function for printing statististical %information for data of scalar time variables variableName to command %line (fid=1) or file (specified by file identifier fid) @@ -23,7 +23,7 @@ function printTable(obj, fid, variableName, data) % Define formatting strings for title and headline TITLE = ['# TIME STATISTICS - ', variableName]; - HEADLINE = sprintf(['%5s', repmat([obj.separator, '%11s'], 1, 5)],... + HEADLINE = sprintf(['%5s', repmat([separator, '%11s'], 1, 5)],... 'level', 'mean', 'median', 'std', 'min', 'max'); if fid == 1 @@ -43,6 +43,6 @@ function printTable(obj, fid, variableName, data) max(data, [], 2)]; % Print information - fprintf(fid, ['%5d', repmat([obj.separator, '%8.5e'], 1, 5), '\n'],... + fprintf(fid, ['%5d', repmat([separator, '%8.5e'], 1, 5), '\n'],... [1:size(data, 1); permute(statisticalData, [2 1])]); end \ No newline at end of file diff --git a/lib/storage/@LevelDataCollection/saveToFile.m b/lib/storage/@LevelDataCollection/saveToFile.m index f8236c2..d1aca0c 100644 --- a/lib/storage/@LevelDataCollection/saveToFile.m +++ b/lib/storage/@LevelDataCollection/saveToFile.m @@ -21,13 +21,10 @@ function saveToFile(obj, folder, file) % along with this program. If not, see <http://www.gnu.org/licenses/>. % - - % Proceed optional input - if nargin < 2 - folder = obj.foldername; - end - if nargin < 3 - file = obj.filename; + arguments + obj + folder = obj.foldername + file = obj.filename end % Create problem- and method-specific folder diff --git a/lib/storage/@LevelDataCollection/saveToTable.m b/lib/storage/@LevelDataCollection/saveToTable.m index 6f748df..1ec56e3 100644 --- a/lib/storage/@LevelDataCollection/saveToTable.m +++ b/lib/storage/@LevelDataCollection/saveToTable.m @@ -21,12 +21,9 @@ function saveToTable(obj, separator) % along with this program. If not, see <http://www.gnu.org/licenses/>. % - - % Proceed optional input - if nargin < 2 - obj.separator = ','; - else - obj.separator = separator; + arguments + obj + separator {mustBeTextScalar} = ',' end % Create problem- and method-specific folder @@ -37,7 +34,7 @@ function saveToTable(obj, separator) for j = 1:obj.nTimeVariable fid = fopen(obj.foldername + '/' + obj.filename + '_' + ... obj.timeVariable{j} + '.csv', 'w'); - obj.printTable(fid, obj.timeVariable{j}, data{j}); + obj.printTable(fid, obj.timeVariable{j}, data{j}, separator); fclose(fid); end end diff --git a/lib/storage/@LevelDataCollection/set.m b/lib/storage/@LevelDataCollection/set.m index 70b20fa..6ca051f 100644 --- a/lib/storage/@LevelDataCollection/set.m +++ b/lib/storage/@LevelDataCollection/set.m @@ -1,7 +1,7 @@ -function set(obj, jItem, varargin) +function set(obj, jItem, data) %%SET stores specified list of LevelData objects to the indices determined %in the jItem array -% SET(obj, jItem, varargin) +% SET(obj, jItem, data) % Copyright 2023 Philipp Bringmann % @@ -19,17 +19,21 @@ function set(obj, jItem, varargin) % along with this program. If not, see <http://www.gnu.org/licenses/>. % + arguments + obj + jItem + end - % Check type of input - assert(all(isa(varargin{:}, 'LevelData')), ... - 'Arguments must be of class LevelData'); + arguments (Repeating) + data LevelData + end % Number of items and item indices must coincide - assert(length(jItem) == length(varargin), ... + assert(length(jItem) == length(data), ... 'Number of indices must equal number of given arguments'); % Store items for k = 1:length(jItem) - obj.item{jItem(k)} = varargin{k}; + obj.item{jItem(k)} = data{k}; end end \ No newline at end of file diff --git a/lib/storage/TimeIt.m b/lib/storage/TimeIt.m index 60df811..b437843 100644 --- a/lib/storage/TimeIt.m +++ b/lib/storage/TimeIt.m @@ -1,7 +1,7 @@ -function leveldatacollection = TimeIt(identifier, nRun, functionName, varargin) +function leveldatacollection = TimeIt(identifier, nRun, functionName, arguments) %%TIMEIT function wrapper for multiple runs of functions storing timing %data in LevelData objects -% leveldatacollection = TIMEIT(identifier, nRun, functionName, varargin) +% leveldatacollection = TIMEIT(identifier, nRun, functionName, arguments, ...) % Copyright 2023 Philipp Bringmann % @@ -19,9 +19,14 @@ function leveldatacollection = TimeIt(identifier, nRun, functionName, varargin) % along with this program. If not, see <http://www.gnu.org/licenses/>. % - % Proceed input - if nargin < 4 - varargin = cell(0); + arguments + identifier + nRun + functionName + end + + arguments (Repeating) + arguments end % Welcome statement @@ -37,7 +42,7 @@ function leveldatacollection = TimeIt(identifier, nRun, functionName, varargin) for j = 1:nRun % Run current experiment temporaryIdentifier = sprintf('timingRun%04d', j); - outputList = fevalc(functionName, varargin{:}); + outputList = fevalc(functionName, arguments); leveldata = outputList{1}; leveldata.metaData("identifier") = temporaryIdentifier; % Remove unused information @@ -55,11 +60,11 @@ function leveldatacollection = TimeIt(identifier, nRun, functionName, varargin) end -function output = fevalc(functionName, varargin) %#ok<INUSD> +function output = fevalc(functionName, arguments) %#ok<INUSD> %%FEVALC suppresses output to commandline % Create function call - functioncall = 'feval(functionName, varargin{:})'; + functioncall = 'feval(functionName, arguments{:})'; % Call function [~, output] = evalc(functioncall); % Store output in cell variable -- GitLab