You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
column operator erases complex property
1 view (last 30 days)
Show older comments
Why column (:) changes my data? (R2020b)
>> z=complex(3,0)
z =
3.000000000000000 + 0.000000000000000i
>> isreal(z)
ans =
logical
0
>> isreal(reshape(z,[],1))
ans =
logical
0
>> isreal(z(:)) %%%% <= only column returns 1
ans =
logical
1
21 Comments
Walter Roberson
on 18 Oct 2020
Interesting. I wonder if debugging would show a different data pointer, unlike reshape?
Bruno Luong
on 18 Oct 2020
Edited: Bruno Luong
on 18 Oct 2020
The weird thing is actually no, the pointer stays the the same with format debug
I believe there are a flag of complex in the mxArray structure, this one must (wrongly?) be set by (:)
>> z
Structure address = 1b8e0bac460
m = 1
n = 1
pr = 1b8f7d92e20
3.0000 + 0.0000i
>> reshape(z,[],1)
Structure address = 1b8e0bac460
m = 1
n = 1
pr = 1b8f7d92e20
3.0000 + 0.0000i
>> z(:)
Structure address = 1b8e0bac460
m = 1
n = 1
pr = 1b8f7d92e20
3
VBBV
on 18 Oct 2020
Edited: VBBV
on 18 Oct 2020
Bcoz z is declared using complex function with two arguments, real numbès 3 and 0. The output is one complex number with one row and one col. For which the real part exists and equal to 3.
Use of : operator makes z as vector with two col and one row. So may be using it isreal(z(:)) makes z as real vector with real values only
Bruno Luong
on 18 Oct 2020
Edited: Bruno Luong
on 18 Oct 2020
@Vasishta, Na. Your explanation does not make sense.
z(:)
should be the same as
reshape(z,[],1)
and it's one row one column and I expected it remains complex, as Z.
Matt J
on 18 Oct 2020
Edited: Matt J
on 18 Oct 2020
Even more interestingly, it's not an issue on the GPU,
z=gpuArray(complex(3,0))
isreal(z)
isreal(reshape(z,[],1))
isreal(z(:))
z =
3.0000 + 0.0000i
ans =
logical
0
ans =
logical
0
ans =
logical
0
Walter Roberson
on 18 Oct 2020
Vasishta:
When you use : as the only subscript, the result always has exactly 1 column, even if the original array had dimensions that were only 0 such as zeros(0,0)
VBBV
on 18 Oct 2020
Edited: Walter Roberson
on 19 Oct 2020
@Bruno See the Information in Tips section of the documentation link
VBBV
on 19 Oct 2020
Edited: Walter Roberson
on 19 Oct 2020
@ Bruno
z = complex(12,1);
z =
12.0000 + 1.0000i
isreal(z(:))
ans =
logical
0
So zero is special case
Walter Roberson
on 19 Oct 2020
Edited: Walter Roberson
on 19 Oct 2020
Visashta:
The Tips section of complex() is telling you that complex() is a special function that can explicitly construct variables that have complex part that is all zero, but that the form A+B*i is considered an expression adding A and i*B and that since that is an expression, any all-zero imaginary part will be dropped.
Yes, complex part all-zero is a special case in MATLAB, and the boundaries of that special case are exactly what we are exploring here. It has always been the case that an all-zero complex part will not be lost when you copy or pass a variable, but that it would normally be lost if you use the variable in an expression. The question then arises whether calling reshape() or indexing with (:) should be considered an expression for the purposes of losing the all-zero part. Bruno demonstrated that reshape() does not lose the all-zero complex component, which fits in with the known implementation of reshape() as being about changing the dimension header while using exactly the same data pointer(s) .
Indexing with (:) has long been discussed as being a short-cut for reshape() into a column vector, and if that is the case then because reshape() does not lose the all-zero complex part, it would be unexpected that (:) would lose the all-zero complex part.
We can then ask the question of whether (:) is instead considered an expression rather than just a shortcut to reshape() into a single column. But if it were an expression, then we would expect that for real-valued z, z(:) would copy the data instead of sharing it, leading to a different data pointer. A minor bit of testing shows that is not the case, that when z only contains real values that z(:) shares data.
So... z(:) with complex z is somehow being treated specially, and losing all-zero complex part. z(:) with complex z is giving back a different data pointer.
Next we test
>> format debug
>> z = complex([1 2 3],4)
z =
Structure address = 1dc3db9a0
m = 1
n = 3
pr = 6040044bac60
1.0000 + 4.0000i 2.0000 + 4.0000i 3.0000 + 4.0000i
>> reshape(z,[],1)
ans =
Structure address = 1dc3d95a0
m = 3
n = 1
pr = 6040044bac60
1.0000 + 4.0000i
2.0000 + 4.0000i
3.0000 + 4.0000i
>> z(:)
ans =
Structure address = 1dc3d8d00
m = 3
n = 1
pr = 608005e83260
1.0000 + 4.0000i
2.0000 + 4.0000i
3.0000 + 4.0000i
Notice that when we did the reshape() that the data pointer stayed the same, but when we did the (:) that the data pointer changed. That does not happen when z has no complex part.
>> z1 = [1 2 3]
z1 =
Structure address = 1dc3da500
m = 1
n = 3
pr = 60800d076ca0
1 2 3
>> reshape(z1,[],1)
ans =
Structure address = 1dc3d9c60
m = 3
n = 1
pr = 60800d076ca0
1
2
3
>> z1(:)
ans =
Structure address = 1dc3d8d00
m = 3
n = 1
pr = 60800d076ca0
1
2
3
The problem therefor expands a bit beyond what Bruno originally posted, becoming instead the question:
What is (:) treated like an expression for complex z, but treated as reshape() for non-complex z?
With it being treated as an expression, losing the all-zero part would be automatic.
Paul
on 19 Oct 2020
Edited: Paul
on 19 Oct 2020
Walter,
Would you expect the other types of indexing as I showed above also to be treated like an expression?
Also, doesn't Bruno's orignal example show that that (:) does NOT change the data pointer?
Walter Roberson
on 19 Oct 2020
Bruno's original example shows the same data pointer for scalar z. With non-scalar z, the data pointer is changed.
Other forms of indexing are expected to be treated as an expression.
>> z1 = [1 2 3]
z1 =
Structure address = 1dc3da500
m = 1
n = 3
pr = 60800d076ca0
1 2 3
>> z1(:)
ans =
Structure address = 1ed9c1960
m = 3
n = 1
pr = 60800d076ca0
1
2
3
>> z1(1:3)
ans =
Structure address = 19e7fcb20
m = 1
n = 3
pr = 60800d06ffa0
1 2 3
This is at least consistent between real and complex: this kind of indexing creates new data structures even for real-only data. It is also explicitly documented as creating unshared data: indexing at 1:end in particular is the documented way to create unshared copies of objects (though at the moment I do not recall at the moment whether it creates deep or shallow copies.)
Bruno Luong
on 19 Oct 2020
Edited: Bruno Luong
on 19 Oct 2020
@Vanishta, you miss my point, the COMPLEX command allocates real+imaginary internally, even if imagnary part is 0. That is user intention of using complex command.
The whole purpose of the TIP part of the document is actually tells that user is allowed to create complex array with 0s value in imaginary part.
I expect (:) to preserve that allocation (and keep the data pointer constant) as with RESHAPE. Which is NOT the case.
Why doing such thing, you might ask? Because if I do change a subset of elements of the initial array, it will be faster (assumming array are not shared)
>> format debug
>> z=complex(1:3,0)
z =
Structure address = 2258b2d6a40
m = 1
n = 3
pr = 225a25023c0
1.0000 + 0.0000i 2.0000 + 0.0000i 3.0000 + 0.0000i
>> z(3)=1i % I might do this kind of assigment in for-loop
z =
Structure address = 2258b2d6a40
m = 1
n = 3
pr = 225a25023c0
1.0000 + 0.0000i 2.0000 + 0.0000i 0.0000 + 1.0000i
Unfortunately (:) operator would erase my allocation with COMPLEX.
Bruno Luong
on 28 Mar 2022
Edited: Bruno Luong
on 28 Mar 2022
Some unexpected side-effect that could surprise some users:
z=complex([-2; 1]);
sort(z)
ans =
1.0000 + 0.0000i
-2.0000 + 0.0000i
sortrows(z)
ans = 2×1
1
-2
sort(z(:))
ans = 2×1
-2
1
Walter Roberson
on 28 Mar 2022
Weird! I cannot account for the sort(z) and sortrows() output!
Bruno Luong
on 28 Mar 2022
It seems
- sortrows works on complex input then decide to "cast" the sorted result to real.
- sort(z) does not post cast.
- Whereas sort(z(:)) cast the input first.
Walter Roberson
on 29 Mar 2022
The part I was forgetting was this from sort:
- If A is complex, then by default, sort sorts the elements by magnitude. If more than one element has equal magnitude, then the elements are sorted by phase angle on the interval (−π, π].
But these days there is a 'ComparisonMethod' option, of 'real' or 'magnitude'
Accepted Answer
Walter Roberson
on 18 Oct 2020
For reasons I do not understand, z(:) is being treated as an expression. If you make z larger but complex, then reshape(z,[],1) keeps the same data pointer, but z(:) creates a new data pointer each time -- which is not the case if z is not complex.
I have two speculations at the moment:
- Hypothetically, since array indexing is treated as an expression, Mathworks might have wanted consistency around dropping the complex part of expressions when the complex part was all zero. This explanation is a bit weak as it does not explain why they did not treat reshape() the same way, and does not explain why scalar z keeps the same data pointer (but non-scalar z does not.)
- Hypothetically, it might have to do with the change to representation of complex in R2018a. This explanation is a bit weak as it does not explain why they did not treat reshape() the same way, and does not explain why scalar z keeps the same data pointer (but non-scalar z does not.) On the other hand, this hypothesis has the merit that it would be testable by going back to R2017b and seeing if (:) had the same behaviour there.
7 Comments
per isakson
on 19 Oct 2020
>> z=complex(3,0)
z =
3.0000 + 0.0000i
>> isreal(z)
ans =
logical
0
>> isreal(z(:))
ans =
logical
1
>> version
ans =
'9.3.0.713579 (R2017b)'
>>
Walter Roberson
on 19 Oct 2020
Thanks, per... that eliminates (2) .
z(:) is also supposed to be z(1:end) but z(1:end) is documented as making copies. There thus seems to be a conflict here between whether z(:) is z(1:end) "copied" or is reshape(z,[],1) (uncopied), and that conflict seems to be resolved different ways depending upon whether z is real-only or has complex components.
Bruno Luong
on 19 Oct 2020
Walter; I too guess it's 1).
To me (:) would be less intrusive than what I just discover. I have tendency to use it a lot, but possibly I would think twice now.
Walter Roberson
on 19 Oct 2020
Hmmm... what is the difference between
z(:)
subsref(z,struct('type',{'()'}, 'subs', {{':'}}))
The second of those always creates a new data pointer even for real data, but the first of them does not create a new data pointer for real-valued z, or for scalar complex valued z (but the scalar part potentially loses complex 0)
Jan
on 28 Jul 2021
Edited: Jan
on 28 Jul 2021
Just a check of Per's argument in the current Matlab version:
version
ans = '9.10.0.1716447 (R2021a) Update 4'
z=complex(3, 0)
z = 3.0000 + 0.0000i
isreal(z)
ans = logical
0
isreal(z(:))
ans = logical
1
Did somebody ask MathWorks about this behavior already?
Bruno Luong
on 28 Jul 2021
How to ask TMW a behavior that is not documented nor a bug?
Jan
on 28 Jul 2021
@Bruno Luong: You are Bruno. Just write them an email and ask for an explanation. From time to a developper has called by by phone to explain details concerning a discussion in the forum. They are interested in active users.
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- 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)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)