Diff of /functions/@mmo/subsasgn.m [000000] .. [422372]

Switch to unified view

a b/functions/@mmo/subsasgn.m
1
% SUBSASGN - define index assignment for eegdata objects
2
%
3
% Author: Arnaud Delorme, SCCN, INC, UCSD, Nov. 2008
4
5
% Copyright (C) 2008 Arnaud Delorme, SCCN, INC, UCSD
6
%
7
% This file is part of EEGLAB, see http://www.eeglab.org
8
% for the documentation and details.
9
%
10
% Redistribution and use in source and binary forms, with or without
11
% modification, are permitted provided that the following conditions are met:
12
%
13
% 1. Redistributions of source code must retain the above copyright notice,
14
% this list of conditions and the following disclaimer.
15
%
16
% 2. Redistributions in binary form must reproduce the above copyright notice,
17
% this list of conditions and the following disclaimer in the documentation
18
% and/or other materials provided with the distribution.
19
%
20
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30
% THE POSSIBILITY OF SUCH DAMAGE.
31
32
function obj = subsasgn(obj,ss,val)
33
34
% check empty assignment
35
% -----------------------
36
for index = 1:length(ss(1).subs)
37
    if isempty(ss(1).subs{index}), return; end
38
end
39
40
% remove useless ":"
41
% ------------------
42
while length(obj.dimensions) < length(ss(1).subs)
43
    if isequal(ss(1).subs{end}, ':')
44
        ss(1).subs(end) = [];
45
    else
46
        break;
47
    end
48
end
49
50
% deal with transposed data
51
% -------------------------
52
if obj.transposed, ss = transposeindices(obj, ss); end
53
54
% check stack and local variables
55
% ---------------------
56
ncopies = checkworkspace(obj);
57
if ncopies < 2
58
    s = evalin('caller', 'whos');
59
    for index = 1:length(s)
60
        if strcmpi(s(index).class, 'struct') || strcmpi(s(index).class, 'cell')
61
            tmpVar = evalin('caller', s(index).name);
62
            ncopies = ncopies + checkcopies_local(obj, tmpVar);
63
        elseif strcmpi(s(index).class, 'mmo')
64
            if s(index).persistent || s(index).global
65
                disp('Warning: mmo objects should not be made persistent or global. Behavior is unpredictable.');
66
            end
67
            tmpVar = evalin('caller', s(index).name);
68
            if isequal(tmpVar, obj), ncopies = ncopies + 1; end
69
            if ncopies > 1, break; end
70
        end
71
    end
72
end
73
74
% removing some entries
75
% ---------------------
76
if isempty(val)
77
    newdim1 = obj.dimensions;
78
    newdim2 = obj.dimensions;
79
    
80
    % create new array of new size
81
    % ----------------------------
82
    tmpMMO = memmapfile(obj.dataFile, 'writable', obj.writable, 'format', { 'single' obj.dimensions 'x' });
83
    newFileName = mmo.getnewfilename;
84
    
85
    % find non singleton dimension
86
    % ----------------------------
87
    nonSingleton = [];
88
    ss2 = ss;
89
    for index = 1:length(ss(1).subs)
90
        if ~ischar(ss(1).subs{index}) % can only be ":"
91
            nonSingleton(end+1) = index;
92
            if islogical( ss(1).subs{index}),  ss(1).subs{index} = find( ss(1).subs{index}); end
93
            ss2(1).subs{index} = setdiff_bc([1:newdim1(index)], ss(1).subs{index}); % invert selection
94
        end
95
    end
96
    if length(nonSingleton) > 1, error('A null assignment can have only one non-colon index'); end
97
    if isempty(nonSingleton), obj = []; return; end
98
    
99
    % compute new final dimension and copy data
100
    % -----------------------------------------
101
    if length(ss(1).subs) == 1
102
        fid = fopen(newFileName, 'w');
103
        newdim2 = [ prod(newdim2)-length(ss(1).subs{1}) ];
104
        if ~(newdim1(1) > 1 && all(newdim1(2:end) == 1)), newdim2 = [1 newdim2]; 
105
        else                                              newdim2 = [newdim2 1]; end
106
        newindices = setdiff_bc([1:prod(newdim1)], ss(1).subs{1});
107
        for index = newindices
108
            fwrite(fid, tmpMMO.Data.x(index), 'float');
109
        end
110
        fclose(fid);
111
        fprintf('Warning: memory mapped object writing might not be up to date in cache on network drive');
112
    else
113
        if length(ss(1).subs) < length(newdim2)
114
            newdim2(length(ss(1).subs)) = prod(newdim2(length(ss(1).subs):end));
115
            newdim2(length(ss(1).subs)+1:end) = [];
116
            if nonSingleton == length(ss(1).subs)
117
                ss2(1).subs{end} = setdiff_bc([1:newdim2(end)], ss(1).subs{end});
118
            end
119
        end
120
        newdim2(nonSingleton) = newdim2(nonSingleton)-length(ss(1).subs{nonSingleton});
121
        if ischar(ss2.subs{end})
122
            ss2.subs{end} = [1:prod(newdim1(length(ss2.subs):end))];
123
        end
124
        ss3 = ss2;
125
        fid = fopen(newFileName, 'w');
126
        
127
        % copy large blocks
128
        alllen = cellfun(@length, ss2.subs);
129
        inc = ceil(250000/prod(alllen(1:end-1))); % 1Mb block
130
        for index = 1:inc:length(ss2.subs{end})
131
            ss3.subs{end} = ss2.subs{end}(index:min(index+inc, length(ss2.subs{end})));
132
            tmpdata = subsref(tmpMMO.Data.x, ss3);
133
            fwrite(fid, tmpdata, 'float');
134
        end
135
        fclose(fid);
136
        fprintf('Warning: memory mapped object writing might not be up to date in cache on network drive');
137
    end
138
    
139
    % delete file if necessary
140
    if ncopies == 1 && obj.writable
141
        delete(obj.dataFile);
142
    end
143
    
144
    if obj.debug, disp('new copy created, old deleted (length 1)'); end
145
    obj.dimensions = newdim2;
146
    obj.dataFile = newFileName;
147
    obj.writable = true;
148
    obj = updateWorkspace(obj);
149
    clear tmpMMO;
150
    return;
151
    
152
else
153
    % check size to see if it increases
154
    % ---------------------------------
155
    newdim1 = obj.dimensions;
156
    newdim2 = newdim1;
157
    if length(ss(1).subs) == 1
158
        if ~ischar(ss(1).subs{1}) && max(ss(1).subs{1}) > prod(newdim1)
159
            if length(newdim1) > 2
160
                error('Attempt to grow array along ambiguous dimension.');
161
            end
162
        end
163
        if max(ss(1).subs{1}) > prod(newdim2)
164
            notOneDim = find(newdim2 > 1);
165
            if length(notOneDim) == 1
166
                newdim2(notOneDim) = max(ss(1).subs{1});
167
            end
168
        end
169
    else
170
        if length(newdim1) == 3 && newdim1(3) == 1, newdim1(end) = []; end
171
        if length(ss(1).subs) == 2 && length(newdim1) == 3
172
            if ~ischar(ss(1).subs{2}) && max(ss(1).subs{2}) > prod(newdim1(2:end))
173
                error('Attempt to grow array along ambiguous dimension.');
174
            end
175
            if isnumeric(ss(1).subs{1}), newdim2(1) = max(max(ss(1).subs{1}), newdim2(1)); end
176
        else
177
            for index = 1:length(ss(1).subs)
178
                if isnumeric(ss(1).subs{index})
179
                    if index > length(newdim2)
180
                        newdim2(index) = max(ss(1).subs{index});
181
                    else newdim2(index) = max(max(ss(1).subs{index}), newdim2(index));
182
                    end
183
                end
184
            end
185
        end
186
    end
187
    
188
    % create new array of new size if necessary
189
    % -----------------------------------------
190
    if ~isequal(newdim1, newdim2)
191
        tmpMMO = memmapfile(obj.dataFile, 'writable', obj.writable, 'format', { 'single' obj.dimensions 'x' });
192
        newFileName = mmo.getnewfilename;
193
        
194
        % copy file row by row
195
        % --------------------
196
        fid = fopen(newFileName, 'w');
197
        dim1 = [ newdim1 1 1 1 1 ];
198
        dim2 = [ newdim2 1 1 1 1 ];
199
        tmpdata1 = zeros(prod(dim2(1:1)) - prod(dim1(1:1)), 1, 'single');
200
        tmpdata2 = zeros((dim2(2) - dim1(2))*dim2(1), 1, 'single');
201
        tmpdata3 = zeros((dim2(3) - dim1(3))*prod(dim2(1:2)), 1, 'single');
202
        
203
        % copy new data (copy first array)
204
        % -------------
205
        for index3 = 1:dim1(3)
206
            if dim1(1) == dim2(1) && dim1(2) == dim2(2)
207
                fwrite(fid, tmpMMO.Data.x(:,:,index3), 'float');
208
            else
209
                for index2 = 1:dim1(2)
210
                    if dim1(1) == dim2(1)
211
                        fwrite(fid, tmpMMO.Data.x(:,index2,index3), 'float');
212
                    else
213
                        for index1 = 1:dim1(1)
214
                            fwrite(fid, tmpMMO.Data.x(index1,index2,index3), 'float');
215
                        end
216
                    end
217
                    fwrite(fid, tmpdata1, 'float');
218
                end
219
            end
220
            fwrite(fid, tmpdata2, 'float');
221
        end
222
        fwrite(fid, tmpdata3, 'float');
223
        fclose(fid);
224
        fprintf('Warning: memory mapped object writing might not be up to date in cache on network drive');
225
        
226
        % delete file if necessary
227
        if ncopies == 1 && obj.writable
228
            delete(obj.dataFile);
229
        end
230
        
231
        if obj.debug, disp('new copy created, old deleted'); end
232
        obj.dimensions = newdim2;
233
        obj.dataFile = newFileName;
234
        obj.writable = true;
235
        clear tmpMMO;
236
        
237
        % create copy if necessary
238
        % ------------------------
239
    elseif ncopies > 1 || ~obj.writable
240
        newFileName = mmo.getnewfilename;
241
        copyfile(obj.dataFile, newFileName);
242
        obj.dataFile = newFileName;
243
        obj.writable = true;
244
        if obj.debug, disp('new copy created'); end
245
    else
246
        if obj.debug, disp('using same copy'); end
247
    end
248
    
249
    % copy new data
250
    tmpMMO = memmapfile(obj.dataFile, 'writable', obj.writable, 'format', { 'single' obj.dimensions 'x' });
251
    if ~isa(val, 'mmo')
252
        tmpMMO.Data.x = builtin('subsasgn', tmpMMO.Data.x, ss, val);
253
    else
254
        % copy memory mapped array
255
        if ndims(val) == 2 && (size(val,1) == 1 || size(val,2) == 1)
256
            % vector direct copy
257
            ss2.type = '()';
258
            ss2.subs = { ':' ':' ':' };
259
            tmpMMO.Data.x = builtin('subsasgn', tmpMMO.Data.x, ss, subsref(val,ss2));
260
        else
261
            ss2.type = '()';
262
            ss2.subs = { ':' ':' ':' };
263
            ss3 = ss;
264
            % array, copy each channel
265
            for index1 = 1:size(val,1)
266
                ss2(1).subs{1} = index1;
267
                if ischar(ss(1).subs{1})
268
                    ss3(1).subs{1} = index1;
269
                else
270
                    ss3(1).subs{1} = ss(1).subs{1}(index1);
271
                end
272
                tmpMMO.Data.x = builtin('subsasgn', tmpMMO.Data.x, ss3, subsref(val,ss2));
273
            end
274
        end
275
    end
276
277
    obj = updateWorkspace(obj);
278
    
279
end
280