이 질문을 팔로우합니다.
- 팔로우하는 게시물 피드에서 업데이트를 확인할 수 있습니다.
- 정보 수신 기본 설정에 따라 이메일을 받을 수 있습니다.
오류 발생
페이지가 변경되었기 때문에 동작을 완료할 수 없습니다. 업데이트된 상태를 보려면 페이지를 다시 불러오십시오.
이전 댓글 표시
Dear all!
My aim is to write a class to handle locations in 3-d space (let's call it 'CoordinateClass'). Therefore I need to store the three coordinates (along with - at the moment - three other values) in an array. Each set of coordinate must have a unique ID. These IDs range from 0 to let's say 1e6 and are chosen by the user. The current solution is to use a sparse array. The coordinates are stored in the row corresponding to the ID.
What is the best way to get this scenario into a class? I could define a sparse array as the class property and work with that. But it is not as easy as to use a vector of objects like
C(1) = CoordinateClass([1 1 1 0 0 0]) % 3-d point at (1,1,1) with ID 1
C(100) = CoordinateClass([100 2 1 0 0 0]) % 3-d point at (100,2,1) with ID 100
The index is the user-defined ID. The problem is the memory usage. If I use large ID values all objects below are allocated as well. Is there a way to implement some kind of "sparse object" to decrease memory usage?
Thanks in advance
채택된 답변
You don't want to have a separate C(i) for each coordinate. That will allocate memory very inefficiently. You want a single object which holds your coordinate and other data as an array, e.g.,
classdef CoordinateClass
properties
coordinates;
IDs;
ThreeOtherValues;
end
end
and now you would have
C.coordinates=[1 1 1; 100 2 1; etc...]
C.IDs=[1;100; etc...]
C.ThreeOtherValues=[0 0 0; 0 0 0; etc...]
댓글 수: 11
Hi!
Thank you for your answer! This solution is of course easy to develop and efficient. But it is(in my opinion) not very user-friendly. Suppose in your example the user wants to change the coordinate with the ID 100.
ind = find(C.IDs==100);
C.coordinates(ind, 1:3) = [100 200 1];
If we had an array C(i) we could just say
C(100).coordinates = [100 200 1];
The same applies e.g. if we want to transfor the cartesian coordinates to polar ones, we might just say:
C(100).cart2pol
Or we add two coordinates (with the overloaded 'plus' function) simply with
C(200) = C(100) + C(1);
instead of
ind1 = find(C.IDs==1);
ind100 = find(C.IDs==100);
ind200 = find(C.IDs==200);
C.coordinates(ind200, 1:3) = C.coordinates(ind100, 1:3) + C.coordinates(ind1, 1:3);
(and we don't have to worry for an array C(i) if C(200) exists already as in 'find(C.IDs==200)'). At the moment I'm using a method 'sumcoordinates' that does the work. The same applies for the above example where I use something like
C = C.changecoordinate(100, [100 200 1]);
It makes things a lot easier to use C(i) in my opinion, but the memory problem ... But maybe there is another solution I don't see. Do you have any hints? Thank you very much!
You can overload the class' SUBSREF method to enable any indexing syntax you want. In any case, you would not use FIND. You would do
ind1=(C.IDs==1);
we don't have to worry for an array C(i) if C(200) exists already
If you're not worrying about this, it means you're not pre-allocating = BAD.
Hi Matt!
Thank you for your assistance! I understood that I can 'emulate' some kind of 'sparse behaviour' by using subsref and subsasgn, like you proposed. Anything else is not usable because a large amount of memory is used if I want to use an array of my class with - let's say - 1e7 elements. Even with pre-allocation it even takes quite some time to work with it.
Nevertheless, I don't know how to cope with my class correctly. I have problems calling the class' methods (even after reading e.g. http://www.mathworks.de/de/help/matlab/ref/subsref.html, http://www.mathworks.de/de/help/matlab/matlab_oop/indexed-reference-and-assignment.html#br09ho8, http://www.mathworks.de/matlabcentral/answers/73430, ...)
Here is the clss code
classdef CoordinateClass
properties
Coord;
IDs;
CoordNum;
end
methods
function obj = CoordinateClass(val)
if ((nargin > 0)&& isa(val, 'numeric') && (length(val) == 1))
% we take the input as the maximum number of coordinates to store
CoordMax = val;
else
% default of 10 coordinates
CoordMax = 10;
end
% pre-allocate arrays
obj.Coord = zeros(CoordMax, 3);
obj.IDs = zeros(CoordMax, 1);
obj.CoordNum = 0;
end
function obj = cart2pol(obj, ind)
fprintf('transforming IDs: %s\n', mat2str(obj.IDs(ind)))
val = obj.Coord(ind, 1:3);
[THETA,RHO,Z] = cart2pol(val(:,1), val(:,2), val(:,3));
obj.Coord(ind, 1:3) = [THETA,RHO,Z];
end
function sref = subsref(obj,s)
switch s(1).type
case '.'
% default dot notation
sref = builtin('subsref',obj,s);
case '()'
% index into coordinate array
if length(s) == 1
% find desired coordinate in array of IDs
[~, ind] = intersect(obj.IDs, s.subs{1});
if ~isempty(ind)
% found -> output as double array
sref = obj.Coord(ind, 1:3);
else
% not found -> output empty array
sref = [];
end
return
elseif length(s) == 2
if strcmp(s(2).type, '.') && strcmp(s(2).subs, 'cart2pol')
% we want to transform some coordinates
% find desired coordinate in array of IDs
[~, ind] = intersect(obj.IDs, s(1).subs{1});
if ~isempty(ind)
% transform found coordinates
obj = cart2pol(obj, ind);
end
sref = obj;
return
end
else
sref = builtin('subsref',obj,s);
end
otherwise
sref = [];
end
end
function obj = subsasgn(obj,s, val)
switch s(1).type
case '.'
% default dot notation
obj = builtin('subsasgn',obj,s);
case '()'
if length(s)<2
% find desired coordinate in array of IDs
[~, ind] = intersect(obj.IDs, s.subs{1});
if any(ind)
% found -> coordinate exists -> change
obj.Coord(ind, 1:3) = val;
else
% not found -> create new coordinate
obj.CoordNum = obj.CoordNum + 1;
obj.Coord(obj.CoordNum, 1:3) = val;
obj.IDs(obj.CoordNum) = s.subs{1};
end
return
else
obj = builtin('subsasgn',obj,s);
end
end
end
end
end
And the test script is
clear all
clc
% create object with a maximum of 10 entries
C = CoordinateClass(10);
% set coordinates
C(1) = [1 1 3];
C(100) = [100 1 3];
C(2) = [2 1 2];
% redefine coordinates
C([1 100]) = [1 2 3; 100 2 3];
% does not work -> transformed coordinates are not returned
C(1:2).cart2pol
% does not work because of missing input argument
C.cart2pol
The second problem seems to be easy to solve by improving the subsref function for all possible calls to the class' object. Is this the best solution or is there something I don't see at the moment?
But I don't know where the first problem comes from. Do you have a hint for me?
Thanks again for your help!
I'm not seeing a problem with C(1:2).cart2pol. The object returned clearly has transformed coordinate data.
>> B=C(1:2).cart2pol; B.Coord, C.Coord
transforming IDs: [1;2]
ans =
1.1071 2.2361 3.0000
100.0000 2.0000 3.0000
0.4636 2.2361 2.0000
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
ans =
1 2 3
100 2 3
2 1 2
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
As for C.cart2pol, it is as you say -- you just need to be doing smarter parsing.
Hi Matt!
I thought about setting the new (transformed) object property implicitly, but I see I have to use
C = C(1:2).cart2pol;
to catch the result of the transformation.
I'll try my best to "invent smarter parsing" for my class. Let's see what happens ... ;-)
Thanks again for your help
I thought about setting the new (transformed) object property implicitly, but I see I have to use C = C(1:2).cart2pol; to catch the result of the transformation.
Yes, that's possible. Then, I need a copy method like proposed here: http://www.mathworks.com/matlabcentral/newsreader/view_thread/257925
I will think about this approach.
But, is it true that e.g. with overloaded subsasgn a property set method is not called via
obj = builtin('subsasgn',obj,s, val)
I have to take care of every property set method via a switch/case statement in the '.'-section of subsasgn?
No you never have to explicitly call a property set method. A property's set method will be called implicitly whenever an attempt is made to modify the property apart from exceptions mentioned here
That's true whether the modification is made inside subsasgn() or any other class method.
Ok, I understood this point.
But what I can't figure out is how to do "correct indexing". I changed subsref/subsasgn to extract the index like in the example above. But in the example I call the cart2pol function explicitly, mainly because I didn't find a way to call it via
builtin('subsref', obj, s)
with an additional argument (the extracted index).
Another possibility I found is to store the extracted index in a separate property of the object, use builtin(...) and extract the index in the called method.
The question is: what is the best/prefered way to do this?
EDIT: Why does C.cart2pol go through subsref and cart2pol(C) not?
Why does C.cart2pol go through subsref and cart2pol(C) not?
Because C.cart2pol is an indexing expression and cart2pol(C) is not. I assume you're referring to situations when these expressions are executed outside the class. Inside a class method, neither expression goes through subsref.
Yes, your right, I execute the command from my test script. But inside the class the expression goes through subsref if I call it directly
sref = subsref(obj, s,)
(assumed the overloaded subsref handles this correctly) and not with
sref = builtin('subsref',obj,s);
That's ok.
추가 답변 (0개)
카테고리
도움말 센터 및 File Exchange에서 Class Introspection and Metadata에 대해 자세히 알아보기
참고 항목
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!웹사이트 선택
번역된 콘텐츠를 보고 지역별 이벤트와 혜택을 살펴보려면 웹사이트를 선택하십시오. 현재 계신 지역에 따라 다음 웹사이트를 권장합니다:
또한 다음 목록에서 웹사이트를 선택하실 수도 있습니다.
사이트 성능 최적화 방법
최고의 사이트 성능을 위해 중국 사이트(중국어 또는 영어)를 선택하십시오. 현재 계신 지역에서는 다른 국가의 MathWorks 사이트 방문이 최적화되지 않았습니다.
미주
- América Latina (Español)
- Canada (English)
- United States (English)
유럽
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
