Skip to content

Commit

Permalink
Adds optional validation for whole numbers to validateNumber (#260)
Browse files Browse the repository at this point in the history
* Adds optional validation for whole numbers to validateNumber

* Addresses review comment
  • Loading branch information
DrPaulSharp authored Aug 20, 2024
1 parent d626445 commit 6c6c1c5
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 18 deletions.
20 changes: 10 additions & 10 deletions API/controlsClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
end

function set.updatePlotFreq(obj, val)
validateNumber(val, 'updatePlotFreq must be a number');
validateNumber(val, 'updatePlotFreq must be a whole number', true);
if val < 1
throw(exceptions.invalidValue('updatePlotFreq must be greater or equal to 1'));
end
Expand Down Expand Up @@ -117,16 +117,16 @@
end

function set.maxFuncEvals(obj, val)
obj.maxFuncEvals = validateNumber(val, 'maxFuncEvals must be a number');
obj.maxFuncEvals = validateNumber(val, 'maxFuncEvals must be a whole number', true);
end

function set.maxIterations(obj, val)
obj.maxIterations = validateNumber(val, 'maxIterations must be a number');
obj.maxIterations = validateNumber(val, 'maxIterations must be a whole number', true);
end

% DE controls methods
function set.populationSize(obj, val)
validateNumber(val, 'populationSize must be a number');
validateNumber(val, 'populationSize must be a whole number', true);
if val < 1
throw(exceptions.invalidValue('populationSize must be greater or equal to 1'));
end
Expand Down Expand Up @@ -161,7 +161,7 @@
end

function set.numGenerations(obj, val)
validateNumber(val, 'numGenerations value must be a number');
validateNumber(val, 'numGenerations value must be a whole number', true);
if val < 1
throw(exceptions.invalidValue('numGenerations must be greater or equal to 1'));
end
Expand All @@ -170,15 +170,15 @@

% NS control methods
function set.nLive(obj, val)
validateNumber(val, 'nLive must be a number');
validateNumber(val, 'nLive must be a whole number', true);
if val < 1
throw(exceptions.invalidValue('nLive must be greater or equal to 1'));
end
obj.nLive = val;
end

function set.nMCMC(obj, val)
validateNumber(val, 'nMCMC must be a number');
validateNumber(val, 'nMCMC must be a whole number', true);
if val < 0
throw(exceptions.invalidValue('nMCMC must be greater or equal than 0'));
end
Expand All @@ -203,16 +203,16 @@

% DREAM methods
function set.nSamples(obj,val)
validateNumber(val, 'nSample must be a number ');
validateNumber(val, 'nSamples must be a whole number', true);
if val < 0
throw(exceptions.invalidValue('nSample must be greater or equal to 0'));
end
obj.nSamples = val;
end

function set.nChains(obj,val)
validateNumber(val, 'nChains must be a number ');
if (~(round(val) == val) || val <= 0 || isnan(val) || isinf(val))
validateNumber(val, 'nChains must be a whole number', true);
if val <= 0
throw(exceptions.invalidValue('nChains must be a finite integer greater than 0'));
end
obj.nChains = val;
Expand Down
21 changes: 14 additions & 7 deletions tests/testControlsClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ function testUpdatePlotFreq(testCase)
testCase.verifyEqual(testCase.controls.updatePlotFreq, 5, 'set.updatePlotFreq method is not working')
% bad updatePlotFreq type
testCase.verifyError(@() setUpdatePlotFreq('a'), exceptions.invalidType.errorID);
testCase.verifyError(@() setUpdatePlotFreq(1.5), exceptions.invalidValue.errorID);
testCase.verifyError(@() setUpdatePlotFreq(0), exceptions.invalidValue.errorID);
function setUpdatePlotFreq(value)
testCase.controls.updatePlotFreq = value;
Expand All @@ -118,16 +119,18 @@ function testSimplexArguments(testCase)

testCase.controls.maxFuncEvals = 123;
testCase.verifyEqual(testCase.controls.maxFuncEvals, 123, 'set.maxFuncEvals method is not working')
testCase.verifyError(@setMaxFuncEvals, exceptions.invalidType.errorID); % bad maxFuncEvals type
function setMaxFuncEvals
testCase.controls.maxFuncEvals = 'a';
testCase.verifyError(@() setMaxFuncEvals('a'), exceptions.invalidType.errorID); % bad maxFuncEvals type
testCase.verifyError(@() setMaxFuncEvals(1.5), exceptions.invalidValue.errorID);
function setMaxFuncEvals(value)
testCase.controls.maxFuncEvals = value;
end

testCase.controls.maxIterations = 456;
testCase.verifyEqual(testCase.controls.maxIterations, 456, 'set.maxIterations method is not working')
testCase.verifyError(@setMaxIterations, exceptions.invalidType.errorID); % bad maxIterations type
function setMaxIterations
testCase.controls.maxIterations = 'a';
testCase.verifyError(@() setMaxIterations('a'), exceptions.invalidType.errorID); % bad maxIterations type
testCase.verifyError(@() setMaxIterations(1.5), exceptions.invalidValue.errorID);
function setMaxIterations(value)
testCase.controls.maxIterations = value;
end
end

Expand All @@ -138,6 +141,7 @@ function testDEArguments(testCase)
% bad populationSize type
testCase.verifyError(@() setPopulationSize('a'), exceptions.invalidType.errorID);
testCase.verifyError(@() setPopulationSize(0), exceptions.invalidValue.errorID);
testCase.verifyError(@() setPopulationSize(1.5), exceptions.invalidValue.errorID);
function setPopulationSize(value)
testCase.controls.populationSize = value;
end
Expand Down Expand Up @@ -186,6 +190,7 @@ function setTargetValue(value)
% bad numGenerations type
testCase.verifyError(@() setNumGenerations('a'), exceptions.invalidType.errorID);
testCase.verifyError(@() setNumGenerations(0), exceptions.invalidValue.errorID);
testCase.verifyError(@() setNumGenerations(1.5), exceptions.invalidValue.errorID);
function setNumGenerations(value)
testCase.controls.numGenerations = value;
end
Expand All @@ -198,6 +203,7 @@ function testNSArguments(testCase)
% bad nLive type
testCase.verifyError(@() setnLive('a'), exceptions.invalidType.errorID);
testCase.verifyError(@() setnLive(0), exceptions.invalidValue.errorID);
testCase.verifyError(@() setnLive(1.5), exceptions.invalidValue.errorID);
function setnLive(value)
testCase.controls.nLive = value;
end
Expand All @@ -207,6 +213,7 @@ function setnLive(value)
% bad nMCMC type
testCase.verifyError(@() setnMCMC('a'), exceptions.invalidType.errorID);
testCase.verifyError(@() setnMCMC(-1), exceptions.invalidValue.errorID);
testCase.verifyError(@() setnMCMC(1.5), exceptions.invalidValue.errorID);
function setnMCMC(value)
testCase.controls.nMCMC = value;
end
Expand Down Expand Up @@ -238,6 +245,7 @@ function testDreamArguments(testCase)
% bad nSamples type
testCase.verifyError(@() setNSamples('a'), exceptions.invalidType.errorID);
testCase.verifyError(@() setNSamples(-1), exceptions.invalidValue.errorID);
testCase.verifyError(@() setNSamples(1.5), exceptions.invalidValue.errorID);
function setNSamples(value)
testCase.controls.nSamples = value;
end
Expand Down Expand Up @@ -605,6 +613,5 @@ function testSetProcedureWithCalculate(testCase)

end


end
end
2 changes: 2 additions & 0 deletions tests/testUtilities.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ function testValidateNumber(testCase)
testCase.verifyEqual(validateNumber([1, 2, 3]), [1, 2, 3], 'validateNumber function is not working');
testCase.verifyError(@() validateNumber('a'), exceptions.invalidType.errorID);
testCase.verifyError(@() validateNumber(false), exceptions.invalidType.errorID);
testCase.verifyEqual(validateNumber(-1.6, '', false), -1.6, 'validateNumber function is not working');
testCase.verifyError(@() validateNumber(-1.6, '', true), exceptions.invalidValue.errorID);
end

function testValidateOption(testCase)
Expand Down
8 changes: 7 additions & 1 deletion utilities/validateNumber.m
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
function input = validateNumber(input, message)
function input = validateNumber(input, message, validateInt)
% Checks input is a number and throws an exception with given message.
%
% If validateInt is true, also check that input is a whole number.
%
% validateNumber(2, 'This is not a number');
% validateNumber(2.5, 'This is not a whole number', true);
arguments
input
message {mustBeTextScalar} = 'The input is not a number'
validateInt {mustBeA(validateInt,'logical')} = false
end

if ~isnumeric(input)
throw(exceptions.invalidType(message));
elseif validateInt && mod(input, 1) ~= 0
throw(exceptions.invalidValue(message));
end
end

0 comments on commit 6c6c1c5

Please sign in to comment.