{dec} ##.cxsh stop                          ⍝ Complex shell.

Quote-quad input is interpreted as a complex expression; evaluated using operat-
or  →cx←;  and the result displayed. The input-eval-display loop continues until
terminating string [stop] is input.

We  can  use  simple  expressions  of  complex  values, with primitive functions
(+ - × ÷ * ⍟ | ⌊ ⌈ ∨ ^ ○ , ⍴ ⌽ ⍉ ⊖ and ..),  together with one-line D-functions,
as  long  as  we bear in mind that  all numeric arrays have a hidden first axis,
see →cx←.

Notice  that  the set of primitive functions is extended with dyadic "..", which
is a complex analogy of the →to← function:

        2 4 .. 10               ⍝ sequence (1×4-grid) from 2 4 .. to 10.
    2 4 6 8 10

        mat ← ¯1j1 .. 2j¯1      ⍝ sequence (3×4-grid) from ¯1j1 to 2j¯1.

        mat
    ¯1j1  0j1  1j1  2j1
    ¯1    0    1    2
    ¯1j¯1 0j¯1 1j¯1 2j¯1

        mat * ÷ 2               ⍝ square root of mat.
    0.4551j1.0987  0.7071j0.7071  1.0987j0.4551  1.4553j0.3436
    0j1            0              1              1.4142
    0.4551j¯1.0987 0.7071j¯0.7071 1.0987j¯0.4551 1.4553j¯0.3436

Optional  left  argument  [dec]  (default 10) is the number of decimal places to
display. Restricting the number of decimals, rather than the number of signific-
ant figures, means that numbers close to zero display as 0.

          cxsh''
        1○○1            ⍝ sin(pi) - should be 0.
    0

Compare this with raw APL:

          1○○1          ⍝ sin(pi) - should be 0.
    1.224606354E¯16

(muse:

    The  problem  with  the  above  result  is not that the sin function (1○) is
    inaccurate, but that the value for pi on an IEEE machine is accurate to only
    1 in 2*53.  Increasing  sin's  argument  by one bit in the least significant
    position  flips  the  result  from just above zero to slightly further below
    zero.

           decf '400921FB54442D18'      ⍝ approx big-endian hex rep of pi.
    3.141592654

        1○ decf '400921FB54442D18'      ⍝ sin of    ..      ..      ..
    1.224606354E¯16

        1○ decf '400921FB54442D19'      ⍝ sin of _adjacent_ IEEE FP number.
    ¯3.216285745E¯16
)

See →cx← for more information and details of supported functions.

Technical notes:

It is convenient to separate the code into three subfunctions:

    - input-display loop,
    - expression translation,
    - evaluation of translated expression.

with a calling tree:

    loop    looping function calls:
      \
       eval    evaluation function calls:
         \
         cexp     complex expression translation.

We could code it like this with three named local functions:

    cxsh←{                  ⍝ Complex shell.
    ·   cexp←{              ⍝ expression translation.
    ·   ·   ...
    ·   }
    ·   eval←{              ⍝ expression evaluation.
    ·   ·   rslt←⍎cexp ⍵    ⍝   execute translated expression.
    ·   ·   ...
    ·   }
    ·   loop←{              ⍝ evaluation loop:
    ·   ·   in←⍞            ⍝   input next line,
    ·   ·   ...             ⍝
    ·   ·   ⎕←eval in       ⍝   evaulate line.
    ·   ·   ∇ ⍵             ⍝ ... and so forth.
    ·   }
    ·   loop ⍵              ⍝ loop until ⍵.
    }

However, as we allow the shell to assign global names:

    i ← 0j1

there is potential for a name-clash with one of cxsh's locals. For example, with
the above coding, all bets would be off if our user typed:

      cxsh'stop'        ⍝ start cx session

    eval ← +            ⍝ clobber cxsh's eval function.
    ...                 ⍝ all bets off  :-(

It  is easy to avoid this situation by passing the subsidiary functions as oper-
ands, rather than naming them:         ¯¯¯¯¯¯¯
                  ¯¯¯¯¯¯
    cxsh←{                  ⍝ Complex shell.
    ·   {                   ⍝ cexp
    ·   ·   ...             ⍝   is an operand to
    ·   }{                  ⍝ eval, which
    ·   ·   rslt←⍎⍺⍺ ⍵      ⍝   evaluates the expression and
    ·   ·   ...             ⍝   is an operand to
    ·   }{                  ⍝ loop, which
    ·   ·   in←⍞            ⍝   inputs the next line,
    ·   ·   ⎕←⍺⍺ line       ⍝   evaluates it,
    ·   ·   ...             ⍝   checks termination
    ·   ·   ∇ ⍵             ⍝   continues.
    ·   }⍵
    }

Then  the  ⍎ in the eval function has _no_ local names in scope (rslt is created
dynamically following the execution).


Note that with calling tree:

    loop    looping function calls:
      \
       eval    evaluation function calls:
         \
         cexp     complex expression translation.

loop  and eval are coded as  monadic operators. It would be equally easy to have
a tree:

        loop
        /  \
    cexp    eval

then we would code loop as a _dyadic_ operator and both cexp and eval as operand
functions.  In  general, any binary tree function calling scheme may be coded in
this way.

Finally,  in the interests of tidiness, we wrap the whole loop-eval-cexp derived
function  inside  an outer function running in a temporary namespace. This means
that created names are _local_ to the cxsh session and disappear when the (cxsh)
session terminates.

    cxsh←{                      ⍝ Complex shell.
    ·   (⎕NS'').{               ⍝ operate in temp space.
    ·   ·   {                   ⍝ cexp
    ·   ·   ·   ...             ⍝   is an operand to
    ·   ·   }{                  ⍝ eval, which
    ·   ·   ·   ...             ⍝   is an operand to
    ·   ·   }{                  ⍝ loop.
    ·   ·   ·   ...
    ·   ·   }⍵
    ·   }⍵
    }

However,  this obliges us to space-qualify external names: →cx←, →subs←, →lcase←
and →to←. For example:

    '..' '─'##.subs ⍵           ⍝ input string with [─/..].

Examples:

      4 cxsh')'                     ⍝ start mini-session (4 dec places) ...

    2+3 4 5                         ⍝ no surprises with ...
5 6 7

    0 1 2 3 4 5|7                   ⍝ .. real arithmetic.
7 0 1 1 3 2

    ¯1*÷2                           ⍝ sqrt(¯1) → i. 
0j1

    1j3 + 8j12 ¯2 0j1               ⍝ complex sum,
9j15 ¯1j3 1j4

    1j3 - 8j12 ¯2 0j1               ⍝ difference,
¯7j¯9 3j3 1j2

    1j3 × 8j12 ¯2 0j1               ⍝ product,
¯28j36 ¯2j¯6 ¯3j1

    1j3 ÷ 8j12 ¯2 0j1               ⍝ quotient,
0.2115j0.0577 ¯0.5j¯1.5 3j¯1

    1j3 | 8j12 ¯2 0j1               ⍝ residue,
1j1 ¯2 0j1

    ¯29j53 ∨ ¯1j107                 ⍝ gcd,
7j1

    ¯29j53 ^ ¯1j107                 ⍝ lcm.
¯853j¯329

    2 1.5 .. ¯1                     ⍝ real range.
2 1.5 1 0.5 0 ¯0.5 ¯1

    0j¯1 .. 0j2                     ⍝ imaginary range.
0j¯1
0
0j1
0j2

    cpts ← ¯1j1..1j¯1               ⍝ matrix of compass points.

    12 ○ cpts                       ⍝ phase angles of compass points.
2.3562  1.5708  0.7854
3.1416  0       0
¯2.3562 ¯1.5708 ¯0.7854

⍝ The following few examples probe values of the complex functions around their
⍝ "branch cuts", see →cx← for details:

    sr ← 1e¯20 × ¯1j1..1j¯1         ⍝ small region around origin.

    sqrt←*∘(÷2)                     ⍝ square-root function.

    sqrt ¯1+sr                      ⍝ square-root around ¯1.
0j1  0j1  0j1
0j1  0j1  0j1
0j¯1 0j¯1 0j¯1

    12○ ¯1+sr                       ⍝ phase angle around ¯1.
3.1416  3.1416  3.1416
3.1416  3.1416  3.1416
¯3.1416 ¯3.1416 ¯3.1416

    ¯3○ 0j2+sr                                  ⍝ arctan around 0j2.
¯1.5708j0.5493 ¯1.5708j0.5493 1.5708j0.5493
¯1.5708j0.5493 ¯1.5708j0.5493 1.5708j0.5493
¯1.5708j0.5493 ¯1.5708j0.5493 1.5708j0.5493

⍝ The function for a polygon in the complex plane is particularly simple:

    poly←{0j1*(0..⍵-1)×4÷⍵}         ⍝ ⍵-polygon.

    poly 4                          ⍝ square.
1 0j1 ¯1 0j¯1

    poly 5                          ⍝ pentagon.
1 0.309j0.9511 ¯0.809j0.5878 ¯0.809j¯0.5878 0.309j¯0.9511

    2 × poly 4                      ⍝ larger square.
2 0j2 ¯2 0j¯2

    1j1 × 2 × poly 4                ⍝ rotated larger square.
2j2 ¯2j2 ¯2j¯2 2j¯2

    sqrt←{|+∘|/⍵⍴0j1}               ⍝ square-root (Theodorus of Cyrene?)

    sqrt 2
1.414213562

    sqrt 10
3.16227766

⍝ Comparisons using ≡ are OK:

    {⍵≡1:⍵ ⋄ 1≡2|⍵:∇1+3×⍵ ⋄ ∇⍵÷2}27 ⍝ →osc←
1

⍝ Here are some more expressions involving i, the square-root of ¯1:

    i ← ¯1*÷2                       ⍝ the square-root of ¯1 ...

    i                               ⍝ ... is i.
0j1

    1 + * ○ i                       ⍝ 1-plus-e-to-the-i-pi →Euler←.
0

    i * ¯2 .. 2                     ⍝ powers of i.
¯1 0j¯1 1 0j1 ¯1

    i * i                           ⍝ i-to-the-i is real (!) and the same as ...
0.2079

    *-○÷2                           ⍝ ...  e-to-the-neg-pi-by-two.
0.2079

    i*÷i                            ⍝ likewise, the i'th root of i is real and
4.8105

    *○÷2                            ⍝ ... is the same as e-to-the-pi-by-two and
4.8105

    (+i)*i                          ⍝ ... the same as conjugate-i-to-the-i and
4.8105

    ↑*⍨/i i i i                     ⍝ ... the same as ((i*i)*i)*i.
4.8105
                                                    ⍝  ix
    {(*⍵×0j1)≡(2○⍵)+0j1×1○⍵} ¯1j1 ¯0.9j0.9 .. 1j¯1  ⍝ e   = cos(x)+i sin(x)
1

⍝ and finally ...

    ¯8*÷3                           ⍝ principal cube root of ¯8 (see below).
1j1.7321

    )                               ⍝ termination string.

⍝ Compare the last result above with the result of the same expression
⍝ in non-complex APL:

    ¯8*÷3                           ⍝ real cube root of ¯8 (see above).
¯2

⍝ In general, numbers have 2 square roots, 3 cube roots, ... ⍵ ⍵th roots.
⍝ Traditional (non-complex) APL returns:
⍝   the positive real root, if there is one,
⍝       otherwise, the negative real root, if there is one,
⍝            otherwise, it fails with a domain error.
⍝
⍝ Complex APL can generate all ⍵ roots, so it chooses to return the one with the
⍝ smallest positive phase angle.

See also: cx polar esh decf

Back to: contents

Back to: Dyalog APL

Trouble seeing APL font?