Complex Numbers in STACK
Complex numbers, especially the display of complex numbers, is a surprisingly subtle issue. This is because there is some genuine ambiguity in whether is a single object or the sum of two parts. In mathematics we use this ambiguity to our advantage, but in online assessment we need to be more precise. There are also issues of unary minus, e.g. not displaying . Similarly we typically do not display numbers like , unless of course we want to at which point we need the option to do so!
The general rules when displaying a complex number in Cartesian form "" are
- the real part should always appear to the left of the imaginary part;
- (or whatever symbol is being used for the imaginary unit) should appear on the right of its coefficient if and only if the coefficient is a numerical value. By numerical value, we mean something like but not things like , even if is a constant.
Some examples:
3+2*%i
should display as .3-%i
should display as .-a+b*%i
should display as .-b*%i
should display as (not normally as ).
STACK provides two functions, one which simplifies and one which does not.
display_complex(ex)
takes an expressionex
and tries to display this as a complex number obeying the above rules. In particular, this function makes use of Maxima'srealpart
andimagpart
function to split upex
into real and imaginary parts. To do this it must assumesimp:true
, and so the real and imaginary part will be simplified. For example,display_complex(1+2*%i/sqrt(2))
is displayed as . If you really want then you will need to use the non-simplifying alternative below. This function respects normal conventions, e.g. whenrealpart
returns zero this function will not print , it just prints , etc.disp_complex(a, b)
assumesa
is the real part andb
is the imaginary part (no checking is done). This function (mostly) does not simplify its arguments. Sodisp_complex(0, 2)
will appear as ;disp_complex(2/4, 1)
will appear as ; anddisp_complex(2, 2/sqrt(2))
will appear as . Use the atomnull
if you do not want to print a zero for the real part, or print one times the imaginary part.disp_complex(null, 2)
will appear as anddisp_complex(null, null)
will appear as just . Think ofnull
as a non-printable unit (additive or multiplicative).
There is one exception. In order to pull out a unary minus to the front, disp_complex(a, b)
will simplify b
if b
is not a number and it contains a unary minus. So, for example disp_complex(a, (-b^2)/b)
is displayed . (We might be able to fix this but this edge case requires disproportionate effort: ask the developers if this is essential).
You cannot use these functions to display complex numbers in this form , both these function will always display as .
Display respects the multiplication sign used elsewhere within expressions, so that you may have rather than .
Note that the function display_complex(ex)
returns the inert form disp_complex(a, b)
. The expression disp_complex(a, b)
is an "inert form", which is only used to fine-tune the display. This function is not actually defined and so Maxima always returns it unevaluated. To remove the inert form from an expression, which is needed to manipulate this further, use remove_disp_complex
, e.g., with the following.
p1:disp_complex(a, b);
p2:ev(p1, disp_complex=remove_disp_complex);
(Because null
has two different meanings within an expression it isn't sufficient to just define disp_complex(ex1, ex2) := ex1+ex2*%i
.)
There are occasions when you will need to explicitly add brackets to the displayed form of a complex number, e.g. to emphasise it is a single entity. To add brackets there is a further "inert form" disp_parens
which does nothing but add parentheses when the expression is displayed with the tex()
function. For example,
p1:disp_parens(display_complex(1+%i))*x^2+disp_parens(display_complex(1-%i));
will display as . To remove these inert forms evaluate
p2:ev(p1, disp_complex=remove_disp_complex, disp_parens=lambda([ex],ex));
You must remove inert forms before expressions are evaluated by the potential response tree, for example in the feedback variables. For example, disp_complex(a, b)
is not algebraically equivalent to a+b*%i
.
Polar and Exponential form
A complex number written as is in exponential form or polar form. The Maxima function polarform
re-writes a complex number in this form, however with simp:false
it does not simplify the expressions for the modulus or argument (in STACK). Attempting to re-simplify the expression only returns the number to Cartesian form!
As a minimal example, try the following.
simp:false;
p1:polarform(1+%i);
p2:ev(polarform(1+%i), simp);
p3:ev(p2, simp);
First we have p1
is . Of course, we really need some simplification of the and the values.
Notice the difference between p2
: , and p3
: (which of course is not even either!).
The problem is that in this case ev( ... , simp)
is not idempotent, (i.e. in all cases) and the PHP-maxima connection inevitably passes an expression to and from Maxima multiple times. If simp:true
then we get multiple simplifications, in this example back to p3
.
Instead, use polarform_simp
to rewrite the expression in polar form, and do some basic simplification of and .
simp:false;
p1:polarform_simp(1+%i);
returns p1
as .
Here are some design choices.
- Positive numbers are returned as real numbers, not as . E.g.
polarform_simp(3)
is . - If then this is not displayed. E.g.
polarform_simp(1/sqrt(2)*(-1+%i))
is .
If question level simplification is on, then the value will probably get re-simplified to Cartesian form.
The predicate complex_exponentialp(ex)
determines if is written in complex exponential form, .
Note this test is strict
- we must have ;
- we must have .
- we expect negative real numbers to be written as .
This predicate needs simp:false
. In particular do not test using the ATAlgEquiv
test, which always simplifies its arguments. Instead test with ATCasEqual(complex_exponentialp(ans1),true)
to avoid automatic simplification of ans1
back to Cartesian form before applying the predicate!
An example question is given in the stack library under Topics\Complex_cube_roots.xml
.