Skip to content

Commit

Permalink
Re #1778 hide hash changes behind the interface to simplify its possi…
Browse files Browse the repository at this point in the history
…ble future modifications.
  • Loading branch information
abuts committed Dec 16, 2024
1 parent f1277e8 commit 2ea421e
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 40 deletions.
16 changes: 8 additions & 8 deletions _test/test_IX_classes/test_IX_experiment.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function test_combine_single_runs_eq_headers_changeID(~)

[result,file_id_array,skipped_inputs,this_runid_map] = Input{1}.combine(Input(2:end),true,false);

hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));

data = [data(1:6),data(8:10)];
Expand Down Expand Up @@ -52,7 +52,7 @@ function test_combine_single_runs_changing_ID(~)
Input = num2cell(data);

[result,file_id_array,skipped_inputs,this_runid_map] = Input{1}.combine(Input(2:end),true,false);
hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));


Expand All @@ -76,7 +76,7 @@ function test_combine_empty_change_ID(~)
data = test_IX_experiment.build_IX_array(10);
[result,file_id_array,skipped_inputs,this_runid_map] = data.combine({},true,false);

hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));

for i=1:10
Expand All @@ -102,7 +102,7 @@ function test_combine_multirun_same_headers_works(~)

[result,file_id_array,skipped_inputs,this_runid_map] = Input{1}.combine(Input(2:end),true,true);

hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));


Expand All @@ -128,7 +128,7 @@ function test_combine_multirun_works(~)

[result,file_id_array,skipped_inputs,this_runid_map] = Input{1}.combine(Input(2:end));

hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));

cai = [Input{:}];
Expand All @@ -154,7 +154,7 @@ function test_combine_single_runs_eq_headers(~)
Input = num2cell(data);

[result,file_id_array,skipped_inputs,this_runid_map] = Input{1}.combine(Input(2:end),true,true);
hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));


Expand All @@ -176,7 +176,7 @@ function test_combine_single_runs_eq_headers(~)
function test_combine_empty(~)
[data,fids] = test_IX_experiment.build_IX_array(10);
[result,file_id_array,skipped_inputs,this_runid_map] = data.combine({},true,true);
hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));


Expand Down Expand Up @@ -208,7 +208,7 @@ function test_combine_single_runs_works(~)
Input = num2cell(data);

[result,file_id_array,skipped_inputs,this_runid_map] = Input{1}.combine(Input(2:end));
hash_defined = arrayfun(@(x)~isempty(x.hash_value),result);
hash_defined = arrayfun(@(x)(x.hash_defined),result);
assertTrue(all(hash_defined));


Expand Down
12 changes: 6 additions & 6 deletions _test/test_unique_objects_container/test_hashable_methods.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function test_exposing_hash_array(~)
assertTrue(is_new);


hash_defined = arrayfun(@(x)~isempty(x.hash_value),data);
hash_defined = arrayfun(@(x)(x.hash_defined),data);
assertTrue(all(hash_defined));

S = data.to_struct();
Expand All @@ -36,7 +36,7 @@ function test_exposing_hash_array(~)
rec_data = hashable.from_struct(S);

assertEqual(data,rec_data);
hash_defined = arrayfun(@(x)~isempty(x.hash_value),rec_data);
hash_defined = arrayfun(@(x)(x.hash_defined),rec_data);
assertTrue(all(hash_defined));
end
function test_exposing_hash_value(~)
Expand All @@ -46,7 +46,7 @@ function test_exposing_hash_value(~)
assertTrue(is_new);


hash_defined = arrayfun(@(x)~isempty(x.hash_value),data);
hash_defined = arrayfun(@(x)(x.hash_defined),data);
assertTrue(all(hash_defined));

S = data.to_struct();
Expand All @@ -60,15 +60,15 @@ function test_exposing_hash_value(~)
rec_data = hashable.from_struct(S);

assertEqual(data,rec_data);
hash_defined = arrayfun(@(x)~isempty(x.hash_value),rec_data);
hash_defined = arrayfun(@(x)(x.hash_defined),rec_data);
assertTrue(all(hash_defined));

end

function test_exposing_empty_hash_array(~)
data = test_hashable_methods.build_IX_array(10);

hash_defined = arrayfun(@(x)~isempty(x.hash_value),data);
hash_defined = arrayfun(@(x)(x.hash_defined),data);
assertFalse(any(hash_defined));

S = data.to_struct();
Expand All @@ -86,7 +86,7 @@ function test_exposing_empty_hash_array(~)
function test_exposing_empty_hash_value(~)
data = test_hashable_methods.build_IX_array(1);

hash_defined = arrayfun(@(x)~isempty(x.hash_value),data);
hash_defined = arrayfun(@(x)(x.hash_defined),data);
assertFalse(any(hash_defined));

S = data.to_struct();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
%======================================================================
% partial load and angular transformations.
methods
% ANGULAR TRANSFORMATIONS (is it necessary? A bit overcomplecated
% ANGULAR TRANSFORMATIONS (is it necessary? A bit overcomplicated
% usage)
%------------------------------------------------------------------
function units = get.angular_units(obj)
Expand Down Expand Up @@ -246,7 +246,7 @@
function [val,obj] = check_angular_val(obj,val)
% main over-loadable setter function for goniometer angles
[val,obj] = check_angular_set_(obj,val);
obj.hash_value_ = [];
obj = obj.clear_hash();
end
function uf = get_undef_fields(obj)
% get list of undefined fields
Expand Down Expand Up @@ -289,7 +289,7 @@
% verify interdependent variables and the validity of the
% obtained lattice object
obj = check_combo_arg_(obj);
obj.hash_value_ = [];
obj = obj.clear_hash();
end
function obj = from_bare_struct (obj, S)
%
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
% close ties with such projection.
%
% NOTE:
% Two IX_experiments with the same gonioneter, energy+mode and short
% Two IX_experiments with the same goniometer, energy+mode and short
% filename but with different run_id are considered equal.
%
% Run-id is notionally related to real experimental run, but actually
% have meaning of a tag, which connects particular IX_experiment with
% particular pixel (neutron event). This is the logical connection,
% build at sqw generation and mainteined during operations with sqw
% build at sqw generation and maintained during operations with sqw
% object
%
% Run-id connection with actual experimental run is useful but
Expand Down Expand Up @@ -93,7 +93,7 @@
class(val))
end
obj.filename_ = val;
obj.hash_value_ = [];
obj = obj.clear_hash();
end
%
function fn = get.filepath(obj)
Expand Down Expand Up @@ -146,7 +146,7 @@
disp2str(val));
end
obj.emode_ = val;
obj.hash_value_ = [];
obj = obj.clear_hash();
end

%
Expand All @@ -160,7 +160,7 @@
class(val));
end
obj.en_ = val(:);
obj.hash_value_ = [];
obj = obj.clear_hash();
end
%
function ef = get.efix(obj)
Expand All @@ -172,7 +172,7 @@
'efix (incident energy) can not be negative')
end
obj.efix_ = val;
obj.hash_value_ = [];
obj = obj.clear_hash();
end
%
function mat = get.u_to_rlu(obj)
Expand Down Expand Up @@ -223,7 +223,7 @@
class(val));
end
obj = obj.from_bare_struct(val);
obj.hash_value_ = [];
obj = obj.clear_hash();
end
end
%----------------------------------------------------------------------
Expand Down Expand Up @@ -398,7 +398,7 @@
% verify interdependent variables and the validity of the
% obtained lattice object
obj = check_combo_arg@Goniometer(obj);
obj.hash_value_ = [];
obj = obj.clear_hash();
if isscalar(obj.efix_) && obj.efix_ == 0 && obj.emode_ ~=0
error('HERBERT:IX_experiment:invalid_argument',...
'efix (incident energy) can be 0 in elastic mode only. Emode=%d', ...
Expand Down
45 changes: 31 additions & 14 deletions herbert_core/utilities/classes/@hashable/hashable.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
properties(Dependent,Hidden)
% expose internal hash_value_ value for debugging purposes
hash_value;

% returns true if hash have been calculated and stored with the object
% and false otherwise.
hash_defined; % Provided to simplify possible future hash
% type replacement, e.g. from char value to uint64 or something
% similar.
end

%---------------------------------------------------------------------------
Expand All @@ -25,25 +31,35 @@
%
flds = obj.saveableFields();
end
function obj = clear_hash(obj)
% function clears the hash value, stored with the object.
% Provided as part of interface and should be used
% to allow simple replacement of hash implementation if we
% decide to use different hash type in a future.
obj.hash_value_ = [];
end
function val = get.hash_value(obj)
val = obj.hash_value_;
end
function is = get.hash_defined(obj)
is = ~isempty(obj.hash_value_);
end

function S = to_struct (obj)
% overload to_struct to add hash to it if hash was available
S = to_struct@serializable(obj);
% make hash value
% attach hash value to the resulting structure
S.hash_value = arrayfun(@(x)x.hash_value_,obj,'UniformOutput',false);
end

function [obj,bytestream] = to_hashable_array(obj)
% Function extracts distignuishable information from the
% Function extracts distinguishable information from the
% object to use as the basis for the hash which describes this
% object.
% Extracts and converts into bytestream the values of fields,
% Extracts and converts into byte-stream the values of fields,
% provided by hashableFields method.
% Input:
% obj -- Object or array of objects which are hashable
% obj -- Object or array of objects which are hashable
% Returns:
% obj -- input object,modified if has children hashable
% objects. These objects have their hashes calculated
Expand All @@ -54,21 +70,22 @@
[obj,bytestream] = to_hashable_array_(obj);
end
function [obj,hash,is_calculated] = build_hash(obj)
% Class specific calculation of hash if it is not available
% for this object
% Class specific calculation of hash if it is not already present
% in this object. If it is present, it returns existing value
% of the hash and unchanged object.
%
% Inputs:
% obj -- hashable object or array of objects
% Returns:
% obj -- hashable object or array of objects with hash value(s)
% stored in hash_value_ property(ies).
% hash -- the value of hash, defining state of the object.
% or cellaray of hashes for all objects in array.
% or cellarray of hashes for all objects in array.
% is_calculated
% -- if true, the hash value(s) were calculated at least
% for some objects in the array,
% for some objects in the array or structure of objects.
% If false, all objects have hashes, already attached
% to it so the function have returned stored value.
% to it so the function have returned the stored value.
%
nobj = numel(obj);
is_calculated = false(1,nobj);
Expand All @@ -81,9 +98,9 @@
hash = hash{1};
end
end

function [ok,mess] = equal_to_tol(obj,other_obj,varargin)
% overload for equal_to_tol method. Very crude.
% overload for equal_to_tol method. Very crude.
% expected to be improved for Re #1147
ok = eq(obj,other_obj);
mess=[];
Expand All @@ -98,7 +115,7 @@
% overload from_struct to restore object and set its hash
% if hash was present in the structure
obj = serializable.from_struct(S,varargin{:});
if isfield(S,'hash_value') % protection agains old hashable
if isfield(S,'hash_value') % protection against old hashable
% objects stored without hash values
hash = S.hash_value;
for i=1:numel(hash)
Expand Down Expand Up @@ -128,10 +145,10 @@
methods
function obj = check_combo_arg (obj)
% overload check_combo_arg. Normally arguments have changed
% so existihg hashes should be destroyed. If they are not,
% so existing hashes should be destroyed. If they are not,
% overload this function for your class appropriately
obj = check_combo_arg@serializable(obj);
obj.hash_value_ = [];
obj = obj.clear_hash();
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
% build or restore hash for single hashable object
%
is_calculated = false;
if ~isnan(obj.hash_value_)
if obj.hash_defined
hash = obj.hash_value_;
return;
end
Expand Down

0 comments on commit 2ea421e

Please sign in to comment.