Printing APL Matrices
Vector 6:1, page 64
Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 64
Introduction¶
Existing APL matrix printing capabilities are inadequate in terms of labelling and formatting for all but the simplest applications. Matrices that are larger than the page width of the printer or screen (typically about 80 columns) are wrapped, causing a loss of the original column structure and limiting the usefulness of many APL routines.
This formatting drawback coupled with the lack of column labels in default APL printing programs can result in confusing and aesthetically unsuitable numeric printouts. Therefore, the need exists for a matrix printing program that can present numeric matrices in labelled, columnar formats that are appropriate for business, financial, and statistical applications.
MPR is a matrix printer function that produces a compact, labelled printout of numeric matrices with user-specified row and column labels. (MPR was first used in the menu-driven statistical package ‘Stat 1: A statistical toolbox’ by Jerry M. Brennan and Lawrence H. Nitz, 1988, Kailua, Hawaii: Sugar Mill Software Corporation.) With MPR, matrices of any size can be printed in their entirety since values and labels are printed in segments as is common with other software. Also, certain values can be suppressed, allowing matrices such as ANOVA summary tables or financial reports to be printed with, for example, unnecessary zeros eliminated.
MPR is flexible, allowing considerable user customisation. Default settings include automatic determination of the minimum number of decimal places within each column, suppression of decimal points for integer columns, and default row and column labels. Settings can be changed with the global variables ∆NDEC, ∆LLEN, ⎕PW, and ∆PL. These environment variables are available as preset defaults or can be passed to the routine dyadically (see below for detailed instructions).
Such customisation represents a significant advantage of MPR and supports various applications of the program. For instance, MPR allows the user to print a series of different tables without explicitly formatting each combination of rows and columns, because the correct format for each matrix is automatically determined based on present default settings. This feature is currently accessible in spreadsheet programs such as Lotus 1-2-3, Excel and Quattro, but is not available as a system function in APL.
MPR in APL¶
MPR is a ambivalent function. The right argument consists of the data matrix to be printed. The optional left argument may contain:
- row labels
- column labels
- maximum number of decimals
- maximum label length
- page width
- maximum number of rows in each printed block.
MPR may be used monadically or dyadically. In the monadic instance, the program generates default row and column labels
∆MPR MATRIX
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10
R1 .00 .00 .34 .79 .47 .32 .25 .97 .77 .59
R2 .11 57.67 89.70 73.09 100.62 78.90 13.22 69.90 295.10 197.90
R3 114.28 223.70 95.93 271.23 291.53 229.78 245.23 .00 34.63 79.31
R4 100.94 108.00 206.75 385.47 196.00 .00 .00 .34 .79 .47
Monadically generated default row and column labels.
In the dyadic mode, row and column labels are passed to the program two ways:
(a) through user-created variables
(b) as a character string within quotation marks with rows first and columns second.
In the latter instance, the symbols ⊢ and ⊣ (i.e. left tack and right tack) are used to delimit row labels while ⊂ and ⊃ (i.e. implication and reverse implication) indicate column labels. The symbol / separates items within each of these delimiters:
'ROW COLUMN' ∆MPR MATRIX
FIRST SECOND THIRD FOURTH FIFTH SIXTH SEVENTH EIGHTH NINTH
SALES .00 .00 .34 .79 .47 .32 .25 .97 .77
INVENTORY .11 57.67 89.70 73.09 100.62 78.90 13.22 69.90 295.10
SUPPLIES 114.28 223.70 95.93 271.23 291.53 229.78 245.23 .00 34.63
MISCELLANE 100.94 108.00 206.75 385.47 196.00 .00 .00 .34 .79
TENTH
SALES .59
INVENTORY 197.90
SUPPLIES 79.31
MISCELLANE .47
'⊢/WEEK1/WEEK2/WEEK3/WEEK4⊣⊂/JOE/MARY/SAM/HARRY/ETHEL/BERT/ERNIE/ANN/NANCY/TOM⊃'
∆MPR MATRIX
JOE MARY SAM HARRY ETHEL BERT ERNIE ANN NANCY TOM
WEEK1 .00 .00 .34 .79 .47 .32 .25 .97 .77 .59
WEEK2 .11 57.67 89.70 73.09 100.62 78.90 13.22 69.90 295.10 197.90
WEEK3 114.28 223.70 95.93 271.23 291.53 229.78 245.23 .00 34.63 79.31
WEEK4 100.94 108.00 206.75 385.47 196.00 .00 .00 .34 .79 .47
Dyadic use of MPR utilizing (a) user-defined variables and (b) a delimited, segmented character string to input row and column labels.
All values to be suppressed in the printed matrix are entered within quotation marks between the symbols ⊥ and ⊤. However, MPR only suppresses true zeros. Thus, when decimal places less than the original value are selected, any non-zero decimal fraction that approaches zero (e.g. .00001) is printed as a non-zero number (i.e. .00…n). To suppress very small numbers, the original matrix should be modified with the operation ⌊ (i.e. floor):
'⊥0⊤' ∆MPR MATRIX
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10
R1 .00 .34 .79 .47 .32 .25 .97 .77 .59
R2 .11 57.67 89.70 73.09 100.62 78.90 13.22 69.90 295.10 197.90
R3 114.28 223.70 95.93 271.23 291.53 229.78 245.23 34.63 79.31
R4 100.94 108.00 206.75 385.47 196.00 .00 .34 .79 .47
'⊥0⊤' ∆MPR ⌊ MATRIX
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10
R1
R2 57 89 73 100 78 13 69 295 197
R3 114 223 95 271 291 229 245 34 79
R4 100 108 206 385 196
Value suppression via the left argument (a) without and (b) with use of the floor operator.
In addition to value suppression, the global variables ∆NDEC, ∆PL, ∆LLEN, and ⎕PW can also be modified temporarily via the left argument. Here, the symbols ∩ and ∪ (i.e. cap and cup) are used to delimit environmental values from the row and column labels. The input syntax is ∆NDEC, ∆LLEN, ⎕PW, ∆PL, with the sequence of these variables always preserved. Thus, ∆NDEC, which sets the maximum number of decimal places within the matrix and rounds data accordingly, occupies the first place in the vector. The default setting for this variable is 2. To change this setting, the user need only enter the desired number of maximum decimal places within the delimiting symbols.
The defaults for each of the remaining settings are as follows: ∆LLEN, which sets the length of the row and column labels, equals 10; ⎕PW, which sets the page width, equals 80; and ∆PL, which sets the maximum number of rows in each formatted block, equals 50. For these settings, a negative number must be entered as a placeholder for each variable that will retain its default. For example, the vector ¯1 24 ¯1 ¯1 sets the maximum length for row and column labels for this print call to 24 without changing any of the other default settings; and 6 15 100 ¯1 changes the maximum number of decimal places to 6, label length value to 15, and the page width to 100 (the page width selected must correspond to the width of the printer. If the printer is only 80 columns wide and 100 columns are requested, the remaining 20 columns will be wrapped) without altering the default maximum number of rows per block:
'ROW COLUMN ∩6 15 ¯1 ¯1∪' ∆MPR MATRIX
FIRST SECOND THIRD FOURTH FIFTH SIXTH
SALES .00000 .000015 .340660 .787984 .466541 .324566
INVENTORY .10674 57.670103 89.701031 73.092784 100.618557 78.896907
SUPPLIES 114.27500 223.700000 95.925000 271.225000 291.525000 229.775000
MISCELLANEOUS 100.93750 108.000000 206.750000 385.470588 196.000000 .000000
SEVENTH EIGHTH NINTH TENTH
SALES .252203 .970568 .772726 .587621
INVENTORY 13.216495 69.900000 295.100000 197.900000
SUPPLIES 245.225000 .000000 34.625000 79.312500
MISCELLANEOUS .000015 .340660 .787984 .466541
Dyadic input of variables containing labels and default settings
MPR also accepts values to be suppressed through the left input string. In fact, the optional left argument can be used simultaneously to input row and column labels, default settings, and value suppression:
'⊢/DRUG/TEST/GENDER/DRUG x TEST⊣⊂/SS1/SS2/SS3/SS4/SS5/SS6/SS7/SS8/SS9/SS10⊃∩4
¯1 ¯1∪⊥0⊤' ∆MPR MATRIX
SS1 SS2 SS3 SS4 SS5 SS6 SS7
DRUG .0000 .3407 .7880 .4665 .3246 .2522
TEST .1067 57.6701 89.7010 73.0928 100.6186 78.8969 13.2165
GENDER 114.2750 223.7000 95.9250 271.2250 291.5250 229.7750 245.2250
DRUG x TEST 100.9375 108.0000 206.7500 385.4706 196.0000 .0000
SS8 SS9 SS10
DRUG .9706 .7727 .5876
TEST 69.9000 295.1000 197.9000
GENDER 34.6250 79.3125
DRUG x TEST .3407 .7880 .4665
Explicit row and column labels, temporary modification of the global variables, and value suppression.
In this way, the settings for a particular project can be easily altered without modifying the existing defaults. Some examples of these changes are displayed below:
============================================================================
Option Global Default Delimiters* Example
============================================================================
Row Labels -- R1,R2,...Rn '⊢X⊣' '⊢/WEEK1/WEEK2⊣'
Column Labels -- C1,C2,...Cn '⊂X⊃' '⊂/JOE/MARY⊃'
Row and Column Labels -- R1,Rn..C1,Cn '⊢X⊣⊂Y⊃' '⊢/1/2⊣⊂/A/B⊃'
Variable-Row Labels -- R1,R2,...Rn 'X' 'ROWLABELS'
Variable-Column Labels -- C1,C2,...Cn ' X'** 'COLUMNLABELS'
Variables-Row & Column -- R1,Rn..C1,Cn 'X Y' 'ROW COLUMN'
Maximum decimal places ∆NDEC 2 '∩X∪' '∩4∪'
Maximum label length ∆LLEN 10 '∩¯1 X∪' '∩¯1 15∪'
Maximum page width ⎕PW 80 '∩¯1 ¯1 X∪' '∩¯1 ¯1 120∪'
Maximum rows in block ∆PL 50 '∩¯1 ¯1 ¯1 X∪' '∩¯1 ¯1 ¯1 10∪'
Values suppressed -- -- '⊥X⊤' '⊥0 99⊤'
============================================================================
* X represents the changed default
⊢ left tack
⊣ right tack
⊂ implication
⊃ reverse implication
∩ cap
∪ cup
⊥ ascending tack
⊤ descending tack
**When a column variable is used without a row variable, the variable name
must be preceded by a space.
Changing Defaults via the Optional Left Argument
Jerry M Brennan
University of Hawaii
Honolulu, Hawaii 96822
Appendix: The Function Listings¶
∇ ∆1 ∆MPR X;BLK;BLKRL;CBLK;CL;CLPS;D;DEC;F;FMT;I;II;K;L;LCOLL;LLEN;PL;PW;RBLK;RL;RLPS;S;SEL;SUP;T;Z;b;c;r
[1] ⍝ Matrix print routine. Globals: ∆PL,⎕PW,∆LLEN,∆NDEC
[2] ⍝ Other FNS: MPR∆L MPR∆WCOLD MPR∆CL CSEL BELIM
[3] ⍝--- SYNTAX
[4] ⍝ 'RVARS CVARS' ∆MPR X where RVARS & CVARS are vars containing labels
[5] ⍝ '⊢/A/B/C⊣⊂/D/E/F⊃' ∆MPR X where rows are A B C and cols D E F
[6] ⍝ ' CVARS' ∆MPR X or '⊂/D/E/F⊃' ∆MPR X where RVARS will be R1,R2...Rn
[7] ⍝ 'RVARS' ∆MPR X or '⊢/A/B/C⊣' ∆MPR X where CVARS will be C1,C2...Cn
[8] ⍝ ∆MPR X where RVARS will be R1,R2,...Fn & CVARS will be C1,C2...Cn
[9] ⍝ Uses global ∆NDEC ∆LLEN ⎕PW ∆PL unless included within "∩" and "∪"
[10] ⍝ e.g. 'RVARS CVARS ∩2 10 132 60∪' ∆MPR X uses as many as appear
[11] ⍝ length may be less than 4 use negative numbers for place holders.
[12] ⍝ Value suppression: any #'s placed between ⊥⊤ will be blanked
[13] →LV×⍳0≠⎕NC '∆1' ⋄ ∆1←''
[14] LV:→LM×⍳2=⍴⍴X ⋄ X←(1,⍴X)⍴X
[15] LM:
[16] ⍝--- DEFAULTS
[17] D←4↑⍎(,'∩∪' CSEL ∆1),12⍴' ¯9'
[18] D←(D×(D≥0))+(D<0)×∆NDEC,∆LLEN,⎕PW,∆PL
[19] DEC←D[1] ⋄ LLEN←D[2] ⋄ PW←D[3] ⋄ PL←D[4]
[20] SUP←,'⊥⊤' CSEL ∆1
[21] ∆1←(~Z∨≠\Z←∆1∊'∩∪⊥⊤')/∆1
[22] ⍝--- LABELS
[23] →LA×⍳0≠,⍴∆1
[24] RL←'1 R' MPR∆L X ⋄ CL←MPR∆L X ⋄ →LX
[25] LA:r←~ 0 0 ≡⍴RL←SStoMAT,'⊢⊣' CSEL ∆1 ⋄ c←~ 0 0 ≡⍴CL←SStoMAT,'⊂⊃' CSEL ∆1
[26] →LX×⍳r∧c
[27] ⍝ elim between delims
[28] b←∆1⍳' ' ⋄ →LB×⍳~'⊂'∊∆1 ⋄ ∆1←(~Z∨≠\Z←∆1∊'⊂⊃')/∆1
[29] LB:→LR×⍳~'⊢'∊∆1 ⋄ ∆1←' ',(~Z∨≠\Z←∆1∊'⊢⊣')/∆1 ⋄ b←1
[30] ⍝ ROW LABELS
[31] LR:→LD×⍳r ⋄ →LC×⍳1=b ⋄ RL←⍎b↑∆1 ⋄ ∆1←b↓∆1 ⋄ →LD
[32] LC:RL←'1 R' MPR∆L X ⋄ →LD
[33] ⍝ COL LABELS
[34] LD:→LX×⍳c ⋄ →LE×⍳∧/∆1=' ' ⋄ CL←⍎∆1 ⋄ →LX
[35] LE:CL←'2 C' MPR∆L X
[36] LX:
[37] RL←((1↑⍴RL),LLEN⌊1↓⍴RL)↑RL←tAB RL ⍝ row labels from vector to matrix
[38] CL←((1↑⍴CL),LLEN⌊1↓⍴CL)↑CL←tAB CL ⍝ col labels from vector to matrix
[39] LCOLL←1++/~∧\⌽CL=' ' ⍝ finds length of each col label +1
[40] RLPS←¯1↑RBLK←⌈(⍳1↑⍴X)÷PL ⍝ RBLK is block # for each row. RLPS # blocks
[41] L←0
[42] ⍝ Loop for each block of ROWS
[43] L5:→PAU×⍳RLPS<L←L+1
[44] FMT←DEC MPR∆WCOLD(RBLK=L)⌿X ⍝ FMT[;2] find min # decimals for each col
[45] FMT[;1]←FMT[;1]⌈LCOLL ⍝ finds min width for each col
[46] ⍝ BLKRL←row labs for col blk. CBLK←blk # for each col. CLPS←# col blks
[47] II←I←0 ⋄ CBLK←⍬ ⋄ BLKRL←BELIM(RBLK=L)⌿RL
[48] L54: ⍝ Loop to determine # COLS in each print block for this ROW block.
[49] CBLK←CBLK,(T←+/1>(+\I↓FMT[;1])÷PW-¯1↑⍴BLKRL)/II←II+1
[50] I←I+T ⋄ →L55×⍳I=1↑⍴FMT ⋄ →L54
[51] ⍝ Loop to print each sub block of ROWS & COLS
[52] L55:CLPS←¯1↑CBLK ⋄ K←0
[53] L6:→L5×⍳CLPS<K←K+1
[54] SEL←(CBLK=K)/⍳⍴CBLK ⍝ SEL is cols selected for this print
[55] ⎕TCNL,((¯1↑⍴BLKRL)⍴' '),FMT[SEL;1]MPR∆CL CL[SEL;] ⍝ Print SEL col labels
[56] ⍝ Regular print without value suppression
[57] →sUP×⍳0≠⍴SUP ⋄ BLKRL,(,(CBLK=K)⌿FMT)⍕(RBLK=L)⌿(CBLK=K)/X ⋄ →L6
[58] ⍝ Print with value suppression
[59] sUP:((1,⍴BLKRL)⍴BLKRL), 1 0 ⌿(F[;1]/S∊⍎SUP)⌽[1]((,F←(CBLK=K)⌿FMT)⍕S←(RBLK=L)⌿(CBLK=K)/X),[0.5]' '
[60] →L6
[61] PAU:
∇
∇ C←BELIM C;A
[1] ⍝ elim mult lead & trail blanks for vecs elim trail blank cols for matrix
[2] →(1=⍴⍴C)/L1 ⋄ C←(⌽∨\⌽∨⌿' '≠C)/C ⋄ →0
[3] L1:C←((⌽∨\⌽A)∧∨\A←' '≠C)/C ⍝ elim lead and trail delimiters
[4] C←(~C ⎕SS 2⍴' ')/C ⍝ elim mult delimiters
∇
∇ R←F MPR∆CL L;K;T
[1] ⍝ Spaces col labels L using format F of col widths.
[2] R←'' ⋄ K←0
[3] L1:→0×⍳(1↑⍴L)<K←K+1 ⋄ R←R,(-+/∧\' '=⌽T)⌽T←F[K]↑,L[K;] ⋄ →L1
∇
∇ R←∆2 MPR∆L X;C;D
[1] ⍝ Labels for matrix X. ∆2 gives optional dim and root for labels
[2] ⍝ Default is last dim and root of 'C'.
[3] →L1×⍳0≠⎕NC '∆2' ⋄ ∆2←'C'
[4] L1:→L2×⍳' '∊∆2 ⋄ ∆2←(⍕⍴⍴X),' ',∆2
[5] L2:D←(⍴X)[⍎(∆2⍳' ')↑∆2] ⋄ C←(∆2⍳' ')↓∆2
[6] R←(~∧⌿R=' ')/R←((D,⍴C)⍴C),⍕(D,1)⍴⍳D
[7] R←'¨' tAB(R≠' ')/R←,R,'¨'
∇
∇ R←DEC MPR∆WCOLD M;F;I;K;NC;T;V
[1] ⍝ Determines min col widths for data matrix M
[2] TOP:→ST×⍳2=⍴⍴M ⋄ M←((⍴M),1)⍴M
[3] ST:I←0⌈⌈10⍟(10*-DEC)+⌈⌿|M
[4] F←(NC←1↓⍴M)⍴0 ⋄ →PAU×⍳DEC=0
[5] K←0 ⍝ Column counter loop.
[6] L1:→PAU×⍳NC<K←K+1 ⋄ V←M[;K] ⋄ →L1×⍳∧/V=⌊V ⋄ F[K]←1
[7] L2:→L1×⍳(F[K]=DEC)
[8] →L1×⍳(∧/T=⌊T←V×10*F[K])
[9] F[K]←F[K]+1
[10] →L2
[11] ⍝ 1=space I=integer part F=frac part (F>0)=decimal (¯1=×⌊⌿M)=neg sign
[12] PAU:R←(1+I+F+(F>0)+¯1=×⌊⌿M),[1.5]F
∇
∇ R←D CSEL C;M;S
[1] ⍝ select text between delimiters D form into matrix R
[2] S←⍴R← 0 ¯1 ↓(1↑D)tAB(M∨≠\M←C∊D)/C
[3] R←,R ⋄ R[(R=1↓D)/⍳⍴R]←' ' ⋄ R←S⍴R
∇
∇ V←∆2 tAB V;POS
[1] ⍝ convert vector to matrix
[2] →(1<⍴⍴V)/0 ⍝ esc if already a matrix
[3] →(0=⎕NC '∆2')/L2
[4] →(1≥⍴,∆2)/L1 ⋄ V[(V∊∆2)/⍳⍴V]←1↑∆2
[5] L1:V←(1↑∆2),V
[6] L2:V←(1-(V=1↑V)⍳1)↓V ⍝ remove trail delims
[7] V←(~V ⎕SS 2⍴1↑V)/V ⍝ elim mult delimiters
[8] V←SStoMAT V ⋄ →0
∇
∇ R←SStoMAT V;T
[1] T←V∊1↑V←V,1↑V ⋄ V←(~T)/V ⋄ T←T-1+0,¯1↓T←T/⍳⍴T
[2] T←T∘.≥⍳⌈/0,T←(T≠0)/T ⋄ R←(⍴T)⍴(,T)\V
∇