0
Fixed

COMPLEX (& perhaps ISREAL) method - wrong behavior

john doe 4 years ago updated by Pavel Holoborodko 4 years ago 16

>> c1 = complex(12)
c1 =
12 + 0i

>> isreal(c1)
ans =
0


>> c2 = complex(mp(12))
c2 =
12

>> isreal(c2)
ans =
1

new stuff:


>> complex(0,pi*rand(0,1))
ans =
Empty matrix: 0-by-1


>> complex(0,mp(pi)*rand(0,1))
Error using mp/complex (line 2354)
Input arrays must have the same size.

Under review

Thank you very much for excellent report(s)!


The second issue (complex(0,mp(pi)*rand(0,1))) has been fixed in our trunk - will be available in a few days.

Corner cases with empty inputs are nightmare - code becomes macaroni type.


But the first issue (complex(mp(12))) is not a bug. It is by design :).

Toolbox automatically detects if numbers are complex or real. There is no point to push the user to do this manually.


I believe Matlab allows real numbers (without imaginary part) to assign as complex for historical reasons. Probably they needed to pre-allocate planar memory or similar.


But there is no practical reason for this right now, especially for toolbox where memory architecture is very different. So that toolbox just does nothing if user assigns pure real number as complex - this doesn't influence subsequent math functionality.


Or do you know the case when it is needed from mathematical point of view? I might miss something here.

But the first issue (complex(mp(12))) is not a bug. It is by design :).

Under assumption

"...multiprecision numbers and matrices can be seamlessly used in place of the built-in double entities following standard MATLAB syntax rules.",

paraphrasing laws of robotics, I could formulate the following:


1. A custom toolbox function may not harm a Matlab function.
2. A custom toolbox function may not behave different from homonymous Matlab function under the same interface as the Matlab function.


From Matlab documentation:

z = complex(x) returns the complex equivalent of x, such that isreal(z) returns logical 0 (false).If x is real, then z is x + 0i.If x is complex, then z is identical to x.

More:

>> a = [1 2]
a =
1 2
>> b = [0 0]
b =
0 0
>> complex(a,b)
ans =
1 + 0i 2 + 0i
>> complex(mp(a),mp(b))
ans =
1 2

Matlab say:

If b contains only zeros, then z is complex and the value of all its imaginary components is 0. In contrast, the addition a + 0i returns a strictly real result.

You, as an author, say it's an improvement; I, as a user do not share your opinion. :)


I believe Matlab allows real numbers (without imaginary part) to assign as complex for historical reasons.

Not for historical reasons but for mathematical reasons; any real number is a complex number but not any complex number is a real number.

For this reason "double" class has "isreal" method but not "iscomplex" method :).


But there is no practical reason for this right now, especially for toolbox where memory architecture is very different. So that toolbox just does nothing if user assigns pure real number as complex - this doesn't influence subsequent math functionality.

The solution is very handy; can be added alongside/inside ;) the property ID another boolean property ...


How about influence, I find huge! Try something like;

a = complex(12);
b = complex(mp(12));
if isreal(a) ~= isreal(b)
system('format c: /x /y');
end

I hope you have not done so already! :))


Or do you know the case when it is needed from mathematical point of view? I might miss something here.

Here I am totally agree with you ! :)

Thank you very much for your insights!


Toolbox does follow MATLAB syntax and semantic to the maximum possible extent.

Along the way I add/remove some features (which do not harm the whole idea).


I thought about this particular feature of having real number as complex - I couldn't come up with any mathematical code which can benefit from this. Why it is needed?


I would understand if MATLAB would allow +/- zeros - then this feature would be vital for branch cuts, etc.

But now,when there is only one zero - this feature is pointless from computational point of view.


Could you please educate me with some computational/math code where this might be important?

I haven't seen one so far (possibly working with complex infinities?)


Other math systems have no such feature as well (as far as I know). Usually complexity of numbers are automatically detected and treated as such.


I would greatly appreciate example of real-life code where storage format of a real number is important.

In reality, complex(12) setups the storage format of a number, not the semantic - since it is treated as real number in all mathematical operations anyway. Thus I concluded it was related to legacy storage format in MATLAB.


Please teach me where my reasoning is wrong.

Not crossed my mind for a moment the idea of transforming complex numbers with zero imaginary part in pairs (Re, Im) in memory.
The idea is to
CONCEPTUAL (not in computer memory) treat complex numbers with zero imaginary part as complex numbers and not as real numbers, just as it does Matlab.


Already we have:

M = mprand(1000,1);
>> isreal(M(end))
ans =
     1
>> whos M
  Name         Size            Bytes  Class    Attributes

  M         1000x1             48232  mp

>> z = complex(mp(),1)
z = 
    0 +     1i
 
>> M = [z; M];


>> isreal(M(end))
ans =
     0
whos M
  Name         Size            Bytes  Class    Attributes

  M         1001x1             32264  mp


The problem is not as complex numbers with zero imaginary part receive not the same memory space as those with non-zero imaginary part but as 'Isreal' method results are different from those legitimately expect and which I rely.


For my part I wish you to make them fit in a bit :), but 'isreal' must return the same result as in Matlab.


Without change than the minimum can solve the problem (the problem is not mathematics but programming problem).


% mp.m 
properties (SetAccess = public)
    id
end % properties
properties (Access = protected, Dependent = false)
    Complexity = false  %  default REAL (always scalar)
end %
In addition, small changes in the constructor and 'complex', 'isreal', 'disp' and 'display' methods.

that is all!


Imagine what misfortune can happen if I rely the execution of a vital procedures on the result of test 'isreal(var)'

in the actual conditions.

Complexity for a number, defined as belonging to the set of complex numbers, it is not a matter of ... lottery, if it happens to have nonzero imaginary part then is complex, otherwise it's real. No, it is not so!
Complexity is an attribute (true/false) and its modification is only done algorithmically, not sifting through the numbers to find those with non-zero imaginary part.

This is true for pure theoretical & rigorous world. But for computations, there are a lot of cases when algorithms change numbers from real to complex automatically. All matrix functions detect if input is pure real (even if it is stored as complex) to use real-tailored algorithms since they are way faster. Same for routines which might generate complex outputs, e.g. sqrt(-1), eig, etc.


The system which rigorously treats reals as subset of complex numbers just doesn't exist in practice (I think). Instead complex-rules are applied only where necessary, depending of situation. I tried to investigate this in short notes here: http://www.advanpix.com/2015/10/19/devnotes-1-multiplicative-operations-with-complex-infinity


I promise that I will implement this storage format as soon as I see its importance in some application :).

(The only important case I see is complex infinities, but again MATLAB converts real to complex automatically in this case - so should do the toolbox)

I'm afraid I was not clear enough.
The format is NOT a problem. Period.
The problem, minimum minimorum, is that a number (array) that intentionally was created as COMPLEX is reported by 'isreal' as real (NOT COMPLEX), contrary to documented behavior of the Matlab.

You are absolutely right.


I changed semantic of 'isreal' on purpose, with the idea to improve MATLAB.

Now 'isreal' checks if array is pure real (imag(x)==0), independently of how it was created.


Back then I saw no serious consequences for this change. Probably I need to re-think this.

The system which rigorously treats reals as subset of complex numbers just doesn't exist in practice (I think I'm joking).

All things electronic, energy, radio, etc. mean complex numbers ...


Of course I meant the software, including programming languages and systems like MATLAB, Maple and similar.

If you treat the calculations reliability in complex numbers as a whim of mine, you're wrong.

Ask any other user Matlab (including Advanpix Toolbox) from the control systems, process simulation, energy transport, communications radio plus an infinite number of other high-tech fields if they need reliable computing with complex numbers.


Topic closed (for me at least!).

Also whole family of subs*** methods should be changed, and others. Plus overhead of detecting the pure reals before every operation (one pass over array) and many other complications.


Anyway it is doable of course, but the question is do we need this at all :).

Let me summarize the reasoning.


If you treat the calculations reliability in complex numbers as a whim of mine, you're wrong. Ask any other user Matlab (including Advanpix Toolbox) from the control systems, process simulation, energy transport, communications radio plus an infinite number of other high-tech fields if they need reliable computing withcomplex numbers.

Fact 1.

Storing real numbers as complex with zero imaginary part has no any influence on mathematical functionality of MATLAB itself:


>> A = complex(magic(3),0)
A =
            8 +          0i            1 +          0i            6 +          0i
            3 +          0i            5 +          0i            7 +          0i
            4 +          0i            9 +          0i            2 +          0i
>> lu(A)
ans =
            8            1            6
          0.5          8.5           -1
        0.375      0.54412       5.2941
>> sqrt(A)
ans =
       2.8284            1       2.4495
       1.7321       2.2361       2.6458
            2            3       1.4142

As you see, zero-imaginary part is not carried around. So that MATLAB itself doesn't support rigorous handling of complex numbers. This is very justified strategy, any mathematical software follows it. Toolbox follows this as well. Automatically detect where switching to complex is needed (sqrt(-1), eig, etc.), otherwise rely on reals for speed.


Fact 2.

The MATLAB doesn't support signed zeros - this is the only case where storing reals as complex numbers would have mathematical sense (to work with branch cuts, etc.)


Conclusion.

This feature was designed to optimize storage format, so that you can pre-allocate complex array before computations to avoid reallocations:

x = zeros(n)            % <-- preallocate real array
z = complex(zeros(n))   % <-- preallocate complex array


The only function which is affected by this functionality is isreal.

As follows from the above - isreal is designed to just check the storage format of a number.


Fact 3.

All these attempts to optimize storage format, pre-allocation, etc. for doubles - has very little sense for multi-precision numbers/arrays.


It is long story why - but in short it is because MATLAB doesn't allow creating objects of custom type and keeping them inside MEX, storing just pointers to the objects as property field.


As a result object data have to be moved MEX<-->MATLAB on every operation. In this case pre-allocation hurts a lot - actually it is better to keep size of the objects small (grow as needed) to minimize memory to be transferred.


Toolbox design.

- All complex-related functionality in toolbox is done exactly as in MATLAB, with the exception of isreal.

- We use different storage format, and we can use isreal for more meaningful purpose.


Now it checks if input has zero imaginary part. In fact it generates exactly the same output as original isreal in ALL cases, except when real is stored as complex - which is ignored by mathematical functions in MATLAB anyway, as you see above.


Critics.

In all years of translating MATLAB codes to multiprecision I haven't encountered the case where toolbox version of 'isreal' affected functionality. But there is always a possibility of mistake.


Therefore I would greatly appreciate if you would show computational code where this meaning of 'isreal' might be harmful.

Just want to let you know, that I have extended toolbox with support of "shallow" complex numbers:


>> x = mp(complex(12))
x = 
    12 +     0i

>> isreal(x)
ans =
     0

But, in comparison to MATLAB, toolbox supports complex numbers much more correctly, including branch cuts, signed zeros as imaginary part, etc.


If you are interested in details, I wrote short post with examples for demonstration:

http://www.advanpix.com/2016/04/28/branch-cuts-and-signed-zeros-in-matlab/