Complex Default

*Subject*: [mg3031] Complex Default*From*: evans at gte.net (Mark Evans)*Date*: 24 Jan 1996 10:34:09 -0600*Approved*: usenet@wri.com*Distribution*: local*Newsgroups*: wri.mathgroup*Organization*: GTE Intelligent Network Services, GTE INS*Sender*: mj at wri.com

The following was a suggestion I sent to Wolfram Research some time ago. I am curious what other people think of it. Mark Evans evans at gte.net Gentlemen: This suggestion relates to the use of complex numbers in Mathematica. Mathematica should incorporate a global user setting that shuts off the implicit assumption that undefined variables are complex numbers. When used, this preference setting would mean that instead of In[1]:= realVar Out[1]= realVar In[2]:= Re[realVar] Out[2]= Re[realVar] In[3]:= Im[realVar] Out[3]= Im[realVar] In[4]:= Arg[realVar] Out[4]= Arg[realVar] In[5]:= Abs[realVar] Out[5]= Abs[realVar] we would get some simplifications with $ComplexDefault = False: In[1]:= realVar Out[1]= realVar In[2]:= Re[realVar] (* known *) Out[2]= realVar In[3]:= Im[realVar] (* known *) Out[3]= 0 In[4]:= Arg[realVar] (* known *) Out[4]= 0 In[5]:= Abs[realVar] (* could be +/- realVar; leave unknown *) Out[5]= Abs[realVar] I think you would implement this as a system variable, say $ComplexDefault = [True | False]. The above outputs would correspond to $ComplexDefault = True and $ComplexDefault = False, respectively. It turns out that even when working with phasors, all of my undefined variables are real. Expressions only become complex when I personally insert the imaginary unit. These insertions are the only occurrence of the imaginary unit in all of the computations. Under such circumstances, I have been somewhat frustrated by Mathematica's refusal to simplify expressions on the chance that a complex number might be hiding behind symbols I know to be real. Try, for example, Conjugate[Exp[I x]]. Here was an interesting variant: In[44]:= Timing[Conjugate[Exp[I (kx^2 + ky^2)]]] Out[44]= 2 2 I (kx + ky ) {12.05 Second, Conjugate[E ]} Thus on an PowerMac 8100/80 MHz, it took Mathematica 12 seconds to find out that it did not know how to negate the minus sign in a very simple complex exponential. This was with Roman Maeder's "ReIm" package already loaded. When I defined kx and ky to be real per his package, the time was reduced to 3.5 seconds; still a long time for such a simple thing. This expression is like 2+2. It should be a snap. I suspect this is a problem in the start-up code that pattern-matches the form of the input. This is precisely my point, and it obtains more generally in Mathematica: we want to keep general-purpose symbolic code, but we would also like to see greater convenience in manipulation of expressions with known character. I have perused the ComplexExpand.m package and find that it is encumbered with far too much generality for my purposes. If you experiment with (symbolic) complex numbers, using ComplexExpand[], Conjugate[], Re[], and so on, you will find that even when it is possible to get a final answer, the wait is very long. I have also examined Roman Maeder's "ReIm" package. I like the idea of using upvalues to clarify whether a symbol is real or complex. However, it is a debatable matter how these upvalues should be treated when $ComplexDefault = False. I suppose the way to handle this situation is to stipulate symmetry. Thus $ComplexDefault = False means that an undefined symbol is REAL unless specifically upvalued into a COMPLEX number; and $ComplexDefault = True means the symbol is COMPLEX unless specifically upvalued into a REAL number. It would cost a little bit more time in terms of lookups, but tolerable amounts for completeness' sake. I think this whole concept is philosophically sound as well. The new system variable would be a user-definable statement of his working habits. If you have qualms, consider the following. Quaternions are a generalization of complex numbers, but you don't initialize the Mathematica kernel with the assumption that any undefined symbol can be a quaternion. You stop off at complex numbers, because they are far more common than quaternions. This being the case, why not allow the user to terminate generalizing assumptions at the field of real numbers? Real numbers are far more common than complex numbers, just as complex numbers are far more common than quaternions. The workaround I have developed for now is simply to replace occurences of Complex[a_,b_] with Complex[a,-b]: conj[number_] := number /. {Complex[re_,im_] -> Complex[re, -im]} The rules of complex algebra are such that this simple formula is generally safe. Thus (u1 + u2)* = u1* + u2*, (u1 u2)* = u1* u2*, (u1/u2)* = (u1*/u2*). In these cases the replacement rule works. General algebraic expressions can therefore be input to conj[] and will come out all right. (I would be interested if you think of any problematic cases.) When $ComplexDefault = False, the kernel would still return complex roots, eigenvalues, and the like when asked for them. What we are talking about here are the kernel's internal assumptions about undefined symbols. You might have the kernel issue messages each time the assumption could lead to erroneous output for the sake of unwary users. Personally, I would Off[] this message in my Init.m file. You might well have to implement additional C++ and Mathematica code modules to handle special cases when arguments to various functions can be assumed real. However the resulting speed improvements would probably pay for those efforts. Mark Evans evans at gte.net