Google
 

Trailing-Edge - PDP-10 Archives - decuslib10-12 - 43,50550/form.doc
There are no other files named form.doc in the archive.
.PS 59 70.AP.P 5,0,5.SP 2.FLAG INDEX.FLAG CAPITALIZE
.tp 8.C; FORMAL-SR MATRIX COMPUTATION SYSTEM
.tp 8.C; Allen I. Fleishman, Ph.D.
.tp 8.C; Lederle Laboratories
.SP 1.TITLE FORMAL Document Version 2.2
  Note - this manual has been adapted from an earlier version
originally written by Ledyard R Tucker.
.s 1
 FORMAL is a &F&O&RTRAN &Matrix &Algebra &Library that includes
programs written by Carl Finkbeiner of Proctor and Gamble, Ledyard
R Tucker of the University of Illinois, and Allen I. Fleishman of
Stevens Institute. The programs were modified for Stevens Institute
by Allen Fleishman.
This library provides a number of subroutines
for performing matrix and statistical operations in FORTRAN
computer programs. The subroutines facilitate
writing FORTRAN programs without interfering with their flexibility.
 Advanced FORTRAN users may elect to skip the following introduction
to the FORMAL-SR COMPUTATION SYSTEM and go immediately to the
sections on advanced FORMAL use (e.g., Use of FORMAL with varied or
Non-Square Matrices on page 9 and the subroutines which follow).
 Although this library is sufficiently extensive to permit writing
of complete programs it may be combined with
FORTRAN statements in more extensive programs.
A &Simplified-&Restricted system has been devised
using the FORMAL procedures
in order to provide students with minimal or no knowledge of FORTRAN
a means to obtain computations on matrix problems. This system is
designated the FORMAL-SR MATRIX COMPUTATION SYSTEM and will provide a
working program for many class size problems and projects.
 This library allows the user to perform easy I/O (e.g., titles,
matrix printers, scatterplots), matrix operations (e.g., eigen
roots and vectors, inverses, Kronecker products), elementwise operations
(e.g., reciprocols of all elements, square roots of all elements),
matrix manipulations (e.g., copying matrices, concatenating or partitioning
matrices), and standard operations (e.g., computing correlations, factor
analyses, Monte Carlo programs, ANOVA).
 The standard FORMAL-SR COMPUTATION SYSTEM provides memory units
for  20  matrices,  each matrix having up to 15 rows and up to
15 columns.
Matrices larger than 13
rows or 13 columns should not be used with the FORMAL-SR
MATRIX COMPUTATION SYSTEM,
because some of the subroutines involve restrictions on
matrix sizes to less than the maximum memory unit size.
The number of memory units and their maximum dimensions may be revised for
a particular program.  The procedure for making these revisions
is described below (see note on Revision of Number of
Storage Units and Size of Matrices and Use of FORMAL with
varied or Non-Square Matrices).
 Computations and data handling operations in the FORMAL-SR
MATRIX COMPUTATION SYSTEM are programmed by either a series of CALL
statements to subroutines or simple FORTRAN statements
described in the sections of these notes on classes of operations.
Operation of this system is described in terms of an Outline
of Card Pack on pages 4-5 and an example on pages 5-9. Notes
for revision and extended use of the system follow the example.
.subtitle Type#of#Cards
.index Type of Cards
.s 1
.tp 8.C; Type of Cards
.s 1
 Computations are controlled by a pack of punched cards which
may be classified into four types: accounting cards, system cards,
program cards, and data cards. (See the Outline of Card Pack
on pages 4-5 and the Card Pack for Example on pages 6-7).
 There are
two cards for accounting: one that indicates whose job it is
.index accounting
(the PPN) and a second which indicates the secret password.  These two
cards are in section A of the Outline and are the first two cards
in the Card Pack. The form of these cards is illustrated in the
Card Pack for Example on page 6.
Note that the PPN number (the Programmer Project Number) and the
PASSWORD are fictitious.
 The system cards  appear in several places in the deck. They
.index system cards
are: the first card of section B of the Outline (card 3 in
the Card Pack),
the $INCLUDE and $DATA cards in section E (cards 47 and 48 in the Card Pack),
and the final card in section G (card 55 in the Card Pack).
 In the FORMAL-SR MATRIX COMPUTATION SYSTEM there are
three classes of program cards: invocation cards, operation
.index program cards
cards, and end of program cards; sections B, C, and D respectively
of the Outline.
  The invocation cards are the
.index invocaton cards
last eight cards in section B of the Outline, as well as cards 4-11
of the Card Pack.  Invocation cards are essential for the
FORMAL system, however, revisions of these cards  may be made.
Such revisions are discussed later.
 The end of program cards are given
.index end of program cards
in section D and are cards 45 and 46 of the Card Pack.
 A few general points:
.list.le;All program cards are to begin in column 7 and may
not have anything punched beyond column 72.  This does not
apply to accounting or system cards which
are explicitly stated to begin in column 1 or to
data cards which can have data in any of the 80 columns.
.le;Unless otherwise stated (e.g., in section on Non-square
matrices)
references to rows (or columns) refers to the number
of rows (or columns) to be operated on. This may be
less than: a)#the ^&dimensional\& size of the memory unit (i.e., 'I1')
or b)#the ^&actual\& size of the data set. For example,
one can print out only the first two rows of an input
data set even if the matrix is dimensioned 15#x#15 ('I1 = 15')  and even
if the matrix has more than 2 rows of data (e.g., 5
rows of data). That is, line 18 of the Card
pack could have been 'CALL#PRINT#(S1,#2,#3,#'F')'.
.le;Variables are of two basic types:
.index Integer variables
 (1) Integers - these variables always begin with a letter from
I to N (a useful mnemonic is to remember the name '&I&Nteger').
Integers are always whole numbers and never contain a decimal
place. Commonly seen  integers as used in these programs
are: the number of rows (often abbreviated 'nr'), the options
and the flags (e.g., iopt or iflag).
.index Floating point variables
 (2) Floating point (or 'F') - these variables always begin
with a letter from A to H or O to Z.  Floating point variables
.index F variable
can take on fractional values.  The most frequently seen 'F' variable
is data (this is true even if the data you happen to have is always
a whole number).
 As a safe rule of thumb, if you create a variable with the same
first letter as the first letter of the program's variables, no errors
will be made. However if the variable was to look like nr (an integer
variable)  and you
supplied a constant called ROWS (an 'F' variable), an error will be made
and the computer may not be smart enough to realize it!!!
.le;Spaces may appear freely between words (see below).
.le;FORTRAN constants and CALL statements may be intermingled
(i.e., one can create a constant anywhere in the program).
.le;Within a
program description , matrices generally appear in the following
order: 1) input matrices (i.e., matrices needed to
obtain results) and 2) output matrices.
All matrices are signified
by a capital S and an upper case letter (e.g., I, J, K).
The upper case letter signifies a particular matrix. For
example, in the TRNSP (matrix transpose) program as described on
page 22, the first matrix, SI, is the matrix that the user wants to
transpose, and SJ, the second matrix, is the transposed
matrix.
.end list
 All program cards from Sections B, C, and D (in general all cards
which are to begin from column 7) are 'free field'. That is, >spaces
are ignored. Of course you cannot put a space in the middle of a
word (e.g., CA__LL, S__10, and SCA__ML are all invalid words).
However spaces around words or punctuation are possible and
often aid in reading (e.g., you may notice the spaces after SUB and
after the commas in line 28). A second useful technique is to put >comment
cards into programs. Comment cards have a 'C' in the first column.
The remainder of the card is ignored. Therefore you can write a
message to yourself as a reminder of the purpose of the program
(or section of the program) and the meaning of each variable.
You may misplace your general notes of a program, but if the
notes are imbedded within the computer deck they will always
be available.
 The operation cards contain the details of the computations to be
.index operation cards
performed. The computations  utilize various subroutines in the FORMAL library
and FORTRAN program statements. The operation cards are indicated
in section C of the Outline and are illustrated by cards 12-44
of the Card Pack for Example. Data is read into the computer
by methods described in the section Data Input. In the example,
cards 12-15 follow the procedure described for Definition of Constants
by Simple FORTRAN Statements. Card 16 uses the subroutine INPUT
to read a matrix from cards into memory unit S1. Cards 17 and 18
provide printing of a title and the data from memory unit S1  (see
the section on Printing of Results). The operation
called for in the example results in
the printed matrix at the top of page 8. Two general features of
the FORMAL system are illustrated in the statement on card 18,
"CALL#PRINT#(S1,5,3,'F')". The first feature is that
one or more memory units are
seen within the parentheses. These memory units contain
the data involved in the operation to be performed or are the
memory units into which results are to be placed. For the PRINT
statement there is only one memory unit which contains the matrix
to be printed.
The second feature is that the number of rows and the number of columns
of the matrix are indicated as integers, 5 and 3 in the
example (an integer is a number without a decimal). Card 19 illustrates
a third way to enter data into the computer using the subroutine
GENR8 described in the section DATA INPUT. The results of this
operation are titled and printed by the statements in cards 20 and
21 and are shown on page 8. Matrix operations with interspersed
printing of results constitute the remainder of the illustrative
program.  These operations are chosen in accordance with the
mathematics and desired results for the problem.  The program
is composed of a sequence of single step matrix operations. Each
step is defined by a single CALL statement which names: the
operation, the memory units containing the data to be utilized, and
the matrix sizes.
Subsequent sections of these notes provide details for the various operations.
In general, the procedure for writing a computation program
involves defining the computations to be performed as a series
of step by step operations which are translated into a series
.SUBTITLE Type of Cards/Outline of Card Pack
of CALL statements.
 A useful procedure in program writing is to keep a running record
of the matrices in the various memory units.  This record or log is
illustrated on page 7 as a Memory Usage Log for Example.
Each step in the computations is indicated by a CALL statement.
Constant reference to this log helps prevent writing
one result over another matrix that is to be used subsequently.
Writing of one matrix over another matrix
destroys the preceding matrix. The most recently written matrix
remains in the memory unit. Therefore, when a matrix is no longer needed
in subsequent computations or to print results, the
memory unit containing that matrix may be reused to store another
matrix. The record also aids in locating the memory units
containing desired matrices. Management of the usage of memory
units is one of the tricky aspects of computer programming.
 Decks of data cards constitute the fourth class of cards in a
FORMAL-SR MATRIX COMPUTATION SYSTEM program. These decks are
indicated as section F of the Outline and are illustrated by
cards 49-54 of the Card Pack for Example. Each data deck is
preceded by a 'header' card (e.g., illustrated as card 49),
which is followed by the cards containing data. Details for the
data decks are given in the section for DATA INPUT. There should
be a data deck for each matrix read into the computer.
These data decks are placed into the pack in the order by which they are
to be read. In the example there is only one data matrix so that
there is only one data deck.
.subtitle Outline of Card Pack/Example of Computation of FORMAL-SR
.S 1.tp 8.C; Outline of Card Pack
.s 1
A.###Job identification cards.
.lm 7.BR;(Start punching in column 1.)
.br;$JOB name_<p,pn_>/NAME:'your name'
.br;$PASSWORD secret password
.lm 0.s 1
.br
B.###FORMAL-SR invocation cards.
.lm 7.BR
(For the first card start punching in column 1;
.lm 13
punch the remaining seven cards starting in column 7.)
.lm 7.br.sp 1
.br;$FORTRAN
.lm 13.br;IMPLICIT#DOUBLE#PRECISION#(A-H,O-Z)
.br;DIMENSION S1(15,15),S2(15,15),S3(15,15),S4(15,15)
.br;DIMENSION S5(15,15),S6(15,15),S7(15,15),S8(15,15)
.br;DIMENSION S9(15,15),S10(15,15),S11(15,15),S12(15,15)
.br;DIMENSION S13(15,15),S14(15,15),S15(15,15),S16(15,15)
.br;DIMENSION S17(15,15),S18(15,15),S19(15,15),S20(15,15)
.br;COMMON/B/I1
.br;I1=I5
.SP 1.lm 0.s 1
C.###Operation cards consisting of:
.list
.le;CALL statements for FORMAL subroutines (see sections
on FORMAL subroutines);
.le;FORTRAN program statements; and
.le;FORTRAN constants.
.end list
D.###End of program cards.
.lm 13.br;(Start punching in column 7.)
.sp 1.br;STOP
.br;END
.SP 1.lm 0.s 1;E.###Start computation and read data card.
.lm 7.br;(Start punching in column 1.)
.sp 1
$INCLUDE#FORMAL.REL_<1413,546_>/SEARCH
.br;$DATA
.s 1.SP 1.lm 0;F.###Data decks (see section on INPUT).
.s 1;G.###Blue end of job card.
.S 2.tp 8.C;Example of Computations by FORMAL-SR
.s 1
 The following data matrix X contains measures of five objects
on three central attributes.
.s 1.tp 8.C; DATA MATRIX X
.s 1.tp 8.C; #########Central Attribute
.tp 8.C;Object####1####2####3
.s 1
.tp 8.C;##1#######5####4####3
.tp 8.C;##2#######3####1####2
.tp 8.C;##3#######3####3####3
.tp 8.C;##4#######4####2####6
.tp 8.C;##5#######1####0####5
.s 2
Compute the sample mean vector M, the matrix of deviation measures from
the sample means Xd, the sample covariance matrix Cxx, the standard deviation
matrix Sx, and the sample correlation matrix Rxx.
.s 2
^&Mathematical__Notes.\&
.NOFILL.NOJUSTIFY
N	= Number of objects in the sample.
(1)	= A column vector with N entries of 1.0.
M	= Vector of means of attributes = (1/N)(1)'X.
Xd	= X - (1)'M.
Cxx	= [1/(N-1)]Xd'Xd.
Sx	= Diag (Cxx).
Rxx	= Sx##Cxx#Sx#.
.FILL.JUSTIFY
.subtitle Card Pack for Example
.page
.tp 8.C; Card Pack for Example
.s 1.nofill.nojustify.sp 1
Card Number          Information Punched on cards
(not punched)        (start in columns 1 or 7 as appropriate)


 1	$JOB _<1234,567_>/NAME:'SMITH, JOHN'
 2	$PASSWORD HUSH
 3	$FORTRAN
 4	      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
 5	      DIMENSION S1(15,15),S2(15,15),S3(15,15),S4(15,15)
 6	      DIMENSION S5(15,15),S6(15,15),S7(15,15),S8(15,15)
 7	      DIMENSION S9(15,15),S10(15,15),S11(15,15),S12(15,15)
 8	      DIMENSION S13(15,15),S14(15,15),S15(15,15),S16(15,15)
 9	      DIMENSION S17(15,15),S18(15,15),S19(15,15),S20(15,15)
10	      COMMON /B/I1
11	      I1 = 15
12	      RN = 5.0
13	      RNM = RN - 1.0
14	      RNI = 1.0/RN
15	      RNMI = 1.0/RNM
16	      CALL INPUT (S1)
17	      CALL TITLE ('ORIGINAL DATA MATRIX  X',23)
18	      CALL PRINT (S1, 5, 3, 'F')
19	      CALL GENR8 (1.0, S9, 5, 1)
20	      CALL TITLE ('COLUMN VECTOR OF ONES', 21)
21	      CALL PRINT (S9, 5, 1, 'F')
22	      CALL TRNSP (S9, S10, 5, 1)
23	      CALL MATML (S10, S1, S8, 1, 5, 3)
24	      CALL SCAML (RNI, S8, S2, 1, 3)
25	      CALL TITLE ('MEAN VECTOR	X BAR', 18)
26	      CALL PRINT (S2, 1, 3, 'F')
27	      CALL MATML (S9, S2, S8, 5, 1, 3)
28	      CALL SUB	 (S1, S8, S3, 5, 3)
29	      CALL TITLE ('DEVIATION MEASURES MATRIX  X SUB D', 34)
30	      CALL PRINT (S3, 5, 3, 'F')
31	      CALL TRNSP (S3, S8, 5, 3)
32	      CALL MATML (S8, S3, S7, 3, 5, 3)
33	      CALL SCAML (RNMI, S7, S4, 3, 3)
34	      CALL TITLE ('COVARIANCE MATRIX  C SUB XX', 27)
35	      CALL PRINT (S4, 3, 3, 'F')
36	      CALL DIAG  (S4, S8, 3)
37	      CALL SQRT  (S8, S5, 3, 3, -0.00001)
38	      CALL TITLE ('STANDARD DEVIATION MATRIX  S SUB X', 34)
39	      CALL PRINT (S5, 3, 3, 'F')
40	      CALL INVRS (S5, S8, 3)
41	      CALL MATML (S8, S4, S7, 3, 3, 3)
42	      CALL MATML (S7, S8, S6, 3, 3, 3)
43	      CALL TITLE ('CORRELATION MATRIX  R SUB XX', 28)
44	      CALL PRINT (S6, 3, 3, 'F')
45	      STOP
46	      END
47	$INCLUDE FORMAL.REL_<1413,546_>/SEARCH
.subtitle Card Pack for Example/Memory Usage Log for Example
48	$DATA
49	00050003(1X, 3F1.0)  PROBLEM 1 DATA MATRIX
50	1543
51	2312
52	3333
53	4426
54	5105
55	         _<blue end of job card_>
.subtitle Memory Usage Log for Example
.s 2.fill.justify.SP 1
.tp 8.C; Memory Usage Log for Example
.INDEX Memory Usage Log
.s 1
.nofill.nojustify.SP 1
Matrices	Contents
   S1		X - raw data
   S2		M - vector of means
   S3		Xd - matrix of deviation scores
   S4		Cxx - covariance matrix
   S5		Sd - Diag (Cxx) - matrix with standard deviations in
                     diagonal
   S6		Rxx - correlation matrix
   S7		[Xd' Xd],   [INVERSE(Sx)*Cxx]
   S8		(1)'X,  (1)M,   Xd',   DIAGONAL(Cxx),    INVERSE(Sx)
   S9		(1) - column vector of ones
   S10		(1)' - row vector of ones
   S11
   S12
   S13
   S14
   S15
   S16
   S17
   S18
   S19
   S20
.s 1
Constants	Contents
   RN		N
   RNM		(N - 1)
   RNI		1/N
   RNMI		1/(N - 1)
.subtitle Example Output
.INDEX Example Output
.page.nofill.nojustify
			    * F O R M A L *
		   (FORTRAN MATRIX ALGEBRA LIBRARY)
		     DATE: 23-Aug-79   TIME: 14:51

SPECIFICATIONS FOR INPUT MATRIX #  1(LURN =  2):
   NUMBER OF ROWS =   5; NUMBER OF COLS =   3; FORMAT =(1X, 3F1.0)
       (this should be on the above line) PROBLEM 1 DATA MATRIX
DATA READ FROM DATA FILE FRMLIN.DAT
ORIGINAL DATA MATRIX  X
	       1	     2		   3
     1	     5.00000	   4.00000	 3.00000
     2	     3.00000	   1.00000	 2.00000
     3	     3.00000	   3.00000	 3.00000
     4	     4.00000	   2.00000	 6.00000
     5	     1.00000	   0.00000	 5.00000

COLUMN VECTOR OF ONES
	       1
     1	     1.00000
     2	     1.00000
     3	     1.00000
     4	     1.00000
     5	     1.00000

MEAN VECTOR	X BAR
	       1	     2		   3
     1	     3.20000	   2.00000	 3.80000

DEVIATION MEASURES MATRIX  X SUB D
	       1	     2		   3
     1	     1.80000	   2.00000	-0.80000
     2	    -0.20000	  -1.00000	-1.80000
     3	    -0.20000	   1.00000	-0.80000
     4	     0.80000	   0.00000	 2.20000
     5	    -2.20000	  -2.00000	 1.20000

COVARIANCE MATRIX  C SUB XX
.subtitle Example Output/Note of Revision of Storage Units
	       1	     2		   3
     1	     2.20000	   2.00000	-0.45000
     2	     2.00000	   2.50000	-0.75000
     3	    -0.45000	  -0.75000	 2.70000

STANDARD DEVIATION MATRIX  S SUB X
	       1	     2		   3
     1	     1.48324	   0.00000	 0.00000
     2	     0.00000	   1.58114	 0.00000
     3	     0.00000	   0.00000	 1.64317

.subtitle Note on Revision of Number of Storage Units and Size of Matrices
.TP 9
CORRELATION MATRIX  R SUB XX
	       1	     2		   3
     1	     1.00000	   0.85280	-0.18464
     2	     0.85280	   1.00000	-0.28868
     3	    -0.18464	  -0.28868	 1.00000
.fill.justify.s 2
.tp 8.C; Note on Revision of Number of Storage Units and Size of Matrices
.INDEX Revision of matrix sizes
.INDEX Size of Matrices
.INDEX Number of Storage Units
.s 1
 Matrix size may be larger than 15 x 15 for some computing
jobs. This will require two revisions in the invocation cards.
 The first revision is to change the memory unit sizes in the
DIMENSION statements to the desired sizes.
For example, if
20 x 20 memory units are desired, &a&l&l of the DIMENSION statements
would look like the following:
.br;#######DIMENSION S1(20,20),S2(20,20),S3(20,20),S4(20,20)
.br;The matrices must be
square (exception to this rule can be found below).
 A second revision is to change the number '15' in the 'I1#=#15'
statement to the new memory unit size.
Therefore, if the memory units were changed to
20 x 20, the statement would become 'I1#=#20'.
 One can also change the number of storage matrices by
inserting additional (or deleting old) DIMENSION statements.
For example, in the cards above only four matrices are used
(i.e., S5 through S20 were not needed therefore they were
never 'created').
.subtitle Use#of#FORMAL#with#Varied#or#Non-Square#Matrices
.s 1
.tp 8.C; Use of FORMAL with Varied or Non-Square Matrices
.INDEX Varied Matrix dimensions
.INDEX Non-Square Matrices
.s 1
 Matrices may be non-square.  However square matrices are simpler
to use with FORMAL. Frequently a user requires rectangular
matrices where the number of rows (or columns) might be much greater
than the number of columns (or rows) (e.g., data matrix).
Under this condition
prefix the program name with an 'X' (e.g.,
.index 'X' programs
INVRS becomes XINVRS, XTX becomes XXTX). Enter the number of rows
for which you dimensioned each matrix after the first parenthesis.
For example:
.tp 8.lm 7.nofill.nojustify.s 1
IMPLICIT DOUBLE PRECISION (A-H, O-Z)
DIMENSION S1(5,5), S2(100,5),S3(100,5),  S4(5,5)
.
.
.
COMMON /B/ I1
I1 = 5
.
.
.
CALL XINPUT (100,S2)
CALL  INPUT (S1)
CALL XMATML (100,5,100, S2, S1, S3, 20, 3, 3)
CALL XPRINT (100, S3, 100, 5, 'F')
CALL  INVRS (S1, S2, 3)
.lm 0.fill.justify.s 1
 The first three numbers in the XMATML call '(100,5,100,...'
refer to the number of rows in the DIMENSION statement (the first number of
each pair). For example, S2 was dimensioned as &1&0&0 x 5 , S1 was
dimensioned as &5 x 5 and S3 was dimensioned as &1&0&0 x 5.
Also note the order of the numbers is S2, S1, and S3. This is the
order by which you input the matrices for matrix multiplication.
The first number is the row dimension, as seen in the DIMENSION
statement,  for the first matrix used
(i.e., S2) in the Call statement. The second number is the row dimension for
the second matrix used (i.e., S1), etc. These numbers tell FORMAL the
^&largest\& size matrix it can use. The size matrix ^&actually\& input or
created by the program may and typically should be smaller
(and ^&never\& larger) than the
row dimension size. As shown in the above example, S1 and S2
were actually 20#x#3 and 3#x#3 matrices respectively.
Also note that the dimensioned size of the matrices differ (i.e.,
S1 and S2 are different sizes, 5 x 5 and 100 x 5 respectively).
 Please note in this example that the simpler
(non 'X') version of FORMAL can be used with this more advanced
use of FORMAL (e.g., the inverse of matrix S1). However, when the
'non-X' FORMAL-SR MATRIX COMPUTATION SYSTEM is used
the dimensions of &a&l&l matrices within that call
must be: 1)#square, 2)#the same size, and
3)#have size equal to I1 as in line 11 of the Card Pack for Example.
That is, the inverse program operates on S1  and S2.
These matrices are: 1)square matrices, 2)of equal
size (each 5 x 5), and 3) have I1 (or 5) rows and columns.
 In the subroutine descriptions which follow, the 'X' version
follows the simpler version. The variable <>NRMi (or NCMI) will
.index <NCMI
refer to the &Number of &Rows (or &Columns) in the &Main program
for matrix SI (e.g.,  NRM3 above would be 100).
 Not all subroutines have an 'X' version. Specifically, unless a
program  inputs a matrix (e.g., TITLE or PAGE), there
would not be an 'X' version of it (as there is no need for one).
.subtitle Data#Input
.s 1.tp 8.tp 8.C; Data Input
.INDEX Data Input
.s 1
 Three methods for recording values in the computer
for a FORMAL-SR computing job are described.
All values input to this system
should be real numbers. While only the so-called F format will be
considered here, D format is permissable as well. In F format each
value is a number with a decimal. All values are assumed to be
positive unless preceded by a minus sign.
.s 1
 1.##^&Definition__of__Constants__by__Simple__<FORTRAN<__Statements\&
.INDEX Constants
.s 1
 Constant values may be entered into a computing job using
simple FORTRAN statements. For example, a constant
value is the number of objects/subjects
in a sample for which a statistical analysis is to be performed.
Note that all integer constants used in computations
will be converted to real numbers.
The conversion to a real number is accomplished by inclusion of a decimal
point followed by (at least) one zero.
The corresponding real number
in F format for use in a calculation is 13.0 when there are 13
subjects/objects in the sample.
 A very useful sequence of FORTRAN statements is given
below.
.tp 8.lm 7.nofill.nojustify
RN## = n.0
RNM# = RN - 1.0
RNI# = 1.0/RN
RNMI = 1.0/RNM
.lm 0;In these statements:
.lm 7
n    #is the integer number of objects (e.g., 13);
RN    is the symbolic name for the number of objects N;
RNM   is the symbolic name for (N-1);
RNI   is the symbolic name for 1/N; and
RNMI  is the symbolic name for 1/(N-1).
.fill.justify.lm 0
 Note that simple arithmetic operations (e.g., subtraction or division)
are possible. The arithmetic symbols are +, -, *, /, ** for
addition, subtraction, multiplication, division and exponentiation
respectively. Parentheses may be freely used. More advanced
calculations are possible (see any FORTRAN text).
 Any sequence of letters and digits up to six characters long may be used
as the symbolic name for a constant provided that:
.lm 5.i -3;1.
the first character is a letter ^&other\& than I, J, K, L, M, or
N (these characters are for special variables called integers which
can only be whole numbers and can never be fractions); and
.i -3;2. the name of the variable is unique
(i.e., you do not want to forget and change it accidentally).
.s 1.lm 0
 2.##^&Subroutine__<>INPUT\&
.s 1
 This subroutine is used to read a matrix from cards into one of
the matrix memory units. The program statement  to use this
subroutine is (starting in column 7):
.lm 7;CALL INPUT##(SI)
.br;CALL XINPUT (NRMI, SI)
.lm 0;where I is an integer designating the particular memory unit.
When this subroutine is used the data deck must be preceded by a
'header card'. This card will tell FORMAL the number of rows
and the number of columns that will be read in along with
information on how the data is formated in your data deck. The form
of the header card is (starting in column 1):
.lm 4.br
rrrrcccc (format string) deck identification
.lm 0.br
where:
 'rrrr' is a four digit integer equal to the number of rows of the
matrix. You must use (and right justify) all four of the digits.
For example,
if you want to read in 14 rows of data, the first card of your
data deck must begin with '0014';
 'cccc' is a four digit integer equal to the number of columns of the
matrix (as above you must use all digits and right justify the
number);
 'format string' describes the sequence of values in each row of the
matrix (for a simple situation see below or for more information see
format elements in the SPSS manual section 4.6.3 or any FORTRAN
text); and
 'deck identification'
helps: 1)#to identify which data set you are working
with (you may be using FORMAL for two different sets of data)
and 2)#to identify the data set when examining FORMAL
output (it is printed out at the place where the data is read
into the program).
 The simplest situation for a format string occurs when every
value in a row of a matrix involves the following:
the same number of characters,
the same number of decimal places, and all of the values in the row
are punched into one card. In this case the format string has the
form:
.i 7.br;(mX,cFw.d)
.br;where:
 m is a one or two digit integer equal to the number of
card columns to be skipped before a useful data value occurs [initial
columns may be used for card
or subject identification (e.g., 1 for first card/subject,
2 for second, ...)];
 nc is a one or two digit number equal to the number of columns of the
matrix (i.e., number of variables to be read in);
 w is an integer equal to the number of characters used for each
value (e.g., If you are reading in a number like 171.43
do not forget to count the decimal point. Therefore
w would equal 6); and
 d is an integer equal to the number of decimal places in each
value (e.g., since there are two numbers on the right side of the
decimal point above ('43'), d would equal 2).
 Two important points to consider:
.list
.le;In case some of the values are negative, an initial character
space for each value should be reserved for the algebraic sign.
For positive values this character may be blank or set to either
a zero or a plus sign.
.le;It is not necessary to punch a decimal point, the computer
will interpret the last d characters as decimal places when a
decimal point is not punched (e.g., one could read data such as
171.43 from data that is punched in as 17143 using a format of 'F5.2').
.le;Remember that the format string is enclosed in parentheses.
.end list
 For example, consider that the following original factor matrix
is to be punched into a data deck and input to the program.
.sp 1
.i 21;column 1
.tp 8.C;1##0.796 0.394
.tp 8.C;2##0.787 0.447
.tp 8.C;3##0.803 0.350
.tp 8.C;4##0.704 0.365
.tp 8.C;5##0.711 -.575
.tp 8.C;6##0.697 -.524
.tp 8.C;7##0.582 -.610
.tp 8.C;8##0.597 -.528
.tp 8.C;9##0.726 0.286
.SP 1.s 1.br;Note that zeros have been recorded to the left of the
decimal point for all positive numbers so that there are the same
number of characters for each number. A card could be punched for
each row of the above matrix. The first two characters
would be the row number followed by six  characters for the first
value and six more characters for the second value. The fifth and
eleventh characters would be decimal points. The header card would
be either of two forms:
.br.i 7;00090002(2X, F6.3, F6.3) ORIGINAL FACTOR MATRIX
.br;or
.br.i 7;00090002(2X,2F6.3) ORIGINAL FACTOR MATRIX
.br;The first four digits of both forms ('0009') indicate that the matrix
has nine rows and the next four digits of both forms ('0002') indicate
that the matrix has only two columns.
You may think that you see three columns above, but the computer will
ignore (or skip) over the card/row number.
The characters within the parentheses
constitute the 'format string' which describes how the data cards
are punched. The character '2X' indicates that the first two columns
of the card will be ignored.
The 'F'
indicates F format. The '6' indicates six characters are used for the
value. The '3' following the decimal place indicates that there
are three digits after the decimal place. Make note of the following
two features: 1) each description for a group of characters
in a data card is separated from other descriptions
by a comma and zero or more spaces, 2) a blank space is
before each number (e.g.,
'__0.796__0.394'). This blank is read as the first of six characters.
When the computer sees a blank space as data it treats it as a zero.
Therefore the first number above is effectively seen as 00.796 or 0.796.
Since both values in each row of data are punched alike
the second form of the header card may be used. A '2' indicates that
the description 'F6.3' is repeated. An integer preceding the 'F'
of a description indicates the number of consecutive repetitions
of that description.  Another example is presented on line 49 of
the Card Pack for Example on page 6.
.s 1
 3.##^&Special__Matrices\&
.index Special Matrices
.s 1
.list.p 5, 0, 5.lm 0.le;^&Subroutine__<>GENR8\&
 This subroutine is used to create a matrix having the same value
in every cell. The program statement to use this subroutine is:
.i 7;(starting in column 7)
.i 7.br;CALL #GENR8 (a, SI, nr, nc)
.i 7.br;CALL XGENR8 (NRMI, a, SI, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 a is a real number to be inserted into each cell;
 I is an integer designating the memory unit to
contain the matrix;
 nr is an integer equal to the number of rows of the matrix; and
 nc is an integer equal to the number of columns of the matrix.
.s 1.LM 0
.p 5, 0, 5.lm 0.le;^&Subroutine__<>IDENT\&
 This subroutine is used to create an identity matrix of size n.
The program statement is:
.lm 7.br;CALL #IDENT (SI, n)
.br;CALL XIDENT (NRMI, SI, n)
.lm 5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit to
contain the identity matrix; and
 n is an integer equal to the order of the identity matrix (i.e.,
the number of rows and columns).
.end list.lm 0.page.subtitle Printing of Results
.tp 8.C;Printing of Results
.LIST
.p 5, 0, 5.lm 0.le;^&Subroutine__<>TITLE\&
 This subroutine is used to print titles (or any type of message)
on the output.  One frequent use is in the identification of matrices.
The program statement to use this subroutine is:
.i 7;CALL TITLE (' character string or title ', n)
.lm 5.p -3, 0, 5.br;where:
 character string is the title to be printed (this character string is
enclosed in apostrophies and in general apostrophies should not be
included in the character string although an advanced technique could
be used to include apostrophies);
 n is an integer equal to the number of characters in the
character string (count blank spaces as characters).
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>PAGE\&
 This subroutine ejects a page on the output. No computations
are done. It is useful in 'tidying up' the output.
The program statement is:
.br.i 7;CALL PAGE
.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>PRINT\&
 This subroutine is used to print a matrix. The program statement
to use this subroutine is:
.br.i 7;CALL #PRINT (SI, nr, nc, 'F')
.br.i 7;CALL XPRINT (NRMI, SI, nr, nc, 'F')
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the matrix
to be printed;
 nr is an integer equal to the number of rows of the matrix; and
 nc is an integer equal to the number of columns of the matrix.
.lm 0.br
A change may
be made from F format to D format by changing the 'F' to 'D' in
the CALL statement. This change is useful for printing extremely
large or small values. In D format a decimal fraction is printed
in scientific notation. That is, a decimal fraction is
printed containing the significant digits and the location
of the decimal is indicated by a signed integer after the
letter E (for exponent). For
a positive integer the decimal point is moved
to the right and for a negative integer the decimal point is
moved to the left. The absolute value of the integer
indicates the number of places to move the decimal. For example,
-0.55785E+01 is the same as -5.5785 and
+0.13459E-02 is the same as +0.0013459.
.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>PUNCH\&
 This subroutine is used to punch a matrix. The program statement
to use this subroutine is:
.br.i 7;CALL #PUNCH (SI, nr, nc)
.br.i 7;CALL XPUNCH (NRMI, SI, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the matrix
to be punched;
 nr is an integer equal to the number of rows of the matrix; and
 nc is an integer equal to the number of columns of the matrix.
.lm 0
 A FORMAL header card is first punched.  The format of the
data will then be punched in 'D' format (see above).  The first five
columns of each card will be the row number of the matrix and the
second five columns contain the specific card number for that row
as more than one card will often be necessary.  These
two numbers should be ignored when reading from this file.
That is, they are only useful to identify the order of the input.
Finally the data will be punched in '5D14.7' format.  The results will
be output to logical unit '1'.  One may need to 'assign' that unit
(see 'Use at Terminal' section), which is the disk, to other units
(e.g., terminal, line printer). This is because my current site does
^&not\& have a card punch.
.S 1.p 5,0,5.lm 0.le;^&Subroutine__<>PLOT\&
 This subroutine is used to 'draw' scatterplots for all pairs
of variables/columns (i.e., across rows).
The program statement to use this subroutine is:
.br.i 7;CALL #PLOT (SI, nr, nc, iflag)
.br.i 7;CALL XPLOT (NRMI, NCMI, SI, nr, nc, iflag)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the data
to be plotted;
 nr is an integer designating the number of rows of the matrix;
 nc is an integer designating the number of columns of the matrix; and
 iflag is an integer in the range of -2 to +2, indicating the style
the plot is to be printed in:
.P -5,0,1.LM +5.br; -2#=#identify all points without drawing a set of axes;
.br; -1#=#count all points (X = 1 point, 2 = two points, ...#, 9
= nine points, M = more than nine points) without drawing axes;
.br; #0#=#plot the points not in pairs but as successive values
(e.g., for each variable the first datum will be plotted at the first position
in the plot, the second datum will be plotted at the second position,
etc.), there will be no axes and the points will be identified (as if
iflag were -2);
.br; +1#=#count all points (as in iflag#=#-1 above) but draw a set
of axes through center of plot; and
.br; +2#=#identify all points (as in iflag#=#-2 above) but draw a set
of axes (as in +1 above).
.p 5,0,5.lm 0
 Point identification, as in iflag options plus or minus 2,
shall identify only the first 124 points.  The first 26 points
shall be identified as letters 'A' through 'Z', the next 10 points
shall be numbers 0 through 9, and the next 26  points will be
letters 'a' through 'z' (again). This sequence shall be repeated once.
The scaling (upper and lower bounds of the axes) shall depend on only
the first 124 points. See CPLOT to control axes otherwise.
 If nc is set to 1 (i.e., only one variable is to be plotted) a
sequential value plot, as in iflag of 0, will be done.  If iflag
is any value less than -2 or greater than +2 an error will be
identified, but processing will be continued with iflag equal to -1.
 When iflag is 0, the number of columns (nc) must be ^&less\& than
the dimensioned number of columns of the memory unit.
.S 1.p 5,0,5.lm 0.le;^&Subroutine__<>CPLOT\&
 This subroutine is also used to 'draw' scatterplots across all pairs
of variables.
 This program differs from PLOT above in that only data which
is between the minimum and maximum values are plotted.
The boundaries of the plot are given by these minimum and maximum
values, as it is often useful to see points relative to a particular
framework (e.g., plotting factor loadings relative to +1 and -1 or
plotting normal deviates relative to +4 and -4).  The variates within
the call to this subroutine are the same as that in XPLOT with the
exception of xmin, xmax, ymin, and ymax.
The program statement to use this subroutine is:
.br.i 7;CALL #CPLOT (SI, nr, nc, xmin, xmax, ymin, ymax, iflag)
.br.i 7;CALL XCPLOT (NRMI, NCMI, SI, nr, nc, xmin, xmax, ymin, ymax,
.BR.I 6;2#iflag)
.LM 0
.lm +5.p -3,0,5.br;where (in addition to those variables seen above):
 xmin is the minimum value of the first variable to be plotted (and
will be the largest value to be seen on the axes);
 xmax is the maximum value of the first variable to be plotted (and
will be the smallest value to be seen on the axes);
 ymin is the minimum value of the second variable; and
 ymax is the maximum value of the second variable.
.END LIST
.subtitle Matrix Operations
.page.tp 8.C;^&Matrix__Operations\&
.list
.p 5, 0, 5.lm 0.le;^&Subroutine__<>ADD\&
 This subroutine is used to perform matrix addition:
.br.i 7;A#+#B#=#C
.br;Program statement:
.br.i 7;CALL #ADD (SI, SJ, SK, nr, nc)
.br.i 7;CALL XADD (NRMI, NRMJ, NRMK, SI, SJ, SK, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 J is an integer designating the memory unit containing matrix B;
 K is an integer designating the memory unit to contain matrix C;
 nr is an integer equal to the number of rows of the matrices; and
 nc is an integer equal to the number of columns of the matrices.
.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>CHLSK\&
 Given a square, symmetric matrix A which is positive definite, this
subroutine creates a lower triangular matrix B such that:
.br;########A#=#BB'
.br;Program statement:
.br.i 7;CALL #CHLSK (SI, SJ, n)
.br.i 7;CALL XCHLSK (NRMI, NRMJ, SI, SJ, n)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 J is an integer designating the memory unit to contain matrix B; and
 n is an integer equal to the order of A and B.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>COLSM\&
 This subroutine adds the elements down the columns of a
matrix A and stores the results as a row vector in the first
row of a memory unit B. This is equivalent to:
.br;########(1)'A#=#B
.br;where (1)' is a row vector containing nr entries of unity.
.br;Program statement:
.br.i 7;CALL #COLSM (SI, SJ, nr, nc)
.br.i 7;CALL XCOLSM (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 J is an integer designating the memory unit to contain matrix B;
 nr is an integer equal to the number of rows of A; and
 nc is an integer equal to the number of columns of A and B.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>DET\&
 This subroutine computes the determinate of a square, real
matrix. (Note - the order of the matrix must be ^&greater\& than 1 and
^&less\& than the size of the memory units.)
.br;Program statement:
.br.i 7;CALL #DET (SI, D, n, SJ)
.br.i 7;CALL XDET (NRMI, NCMI, NRMJ, NCMJ, SI, D, n, SJ)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the matrix;
 D is a FORTRAN constant to contain the value of the determinant which
may be a separate constant located in the (1,1) cell of a memory unit
Sk which is designated as D;
 n is an integer equal to the number of rows and columns of the matrix
(must be ^&less\& than the size of the memory unit); and
 J is an integer designating a memory unit to be used by the program
and will contain the inverse of the input matrix in case the
determinant is not zero.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>EIGEN\&
 This program is used to find the eigen solution for a symmetric
matrix A:
.br.i 7;A#=#VDV'
.br;where:
 V is an orthonormal matrix containing eigenvectors as
columns; and
 D is a diagonal matrix containing the corresponding eignenroots or
eigenvalues. The eigenvectors and eigenvalues are arranged in
descending algebraic order of the eigenvalues.
.br;Program statement:
.br.i 7;CALL #EIGEN (SI, SJ, SK, n, m)
.br.i 7;CALL XEIGEN (NRMI, NRMJ, NRMK, SI, SJ, SK, n, m)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 J is an integer designating the memory unit to contain matrix V;
 K is an integer designating the memory unit to contain matrix D;
 n is an integer equal to the order of A; and
 m is an integer equal to the number of eigenvectors and eigenvalues
to be output into matrices V and D.
.br;
Note - V is n x m and D is m x m.
.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>GINVR\&
 This subroutine is used to determine the generalized inverse of a
matrix. If Y were the generalized inverse then:
.br.i 7;ABA#=#A
.br;Note - the order of each of the matrices must be greater than 10
and ^&less\& that the size of the memory units.
.br;Program statement:
.br.i 7;CALL #GINVR (SI, SJ, nr, nc, SK, SL, SM)
.br.i 7;CALL XGINVR (NRMI, NRMJ, NRMK, NRML, NRMM, SI, SJ, nr, nc, SK,
.br.i 6;2 SL, SM)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the matrix to
have a generalized inverse computed, A;
 J is an integer designating the memory unit to contain the
generalized   inverse, B;
 nr is an integer equal to the number of rows of the input matrix, A;
 nc is an integer equal to the number of columns of the input matrix, A; and
 K, L, and M are integers designating 'work' matrices (temporary
matrices to be used in the computations).
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>INVRS\&
 This subroutine is used to determine the inverse of a square
matrix.
.br;Note - the order of A must be greater than 1 and less than the
size of the memory units.
.br;Program statement:
.br.i 7;CALL #INVRS (SI, SJ, n)
.br.i 7;CALL XINVRS (NRMI, NCMI, NRMJ, NCMJ, SI, SJ, n)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the input matrix;
 J is an integer designating the memory unit to contain the inverse
of the input matrix;
 n is an integer equal to the number of rows and columns of the
matrices (must be ^&less\& than the size of the memory units).
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>KRONK\&
 This subroutine is used to compute the Kronecker product of two
matrices:
.br.i 7;A#X#B#=#C
.br;Note - the size of matrix C must be the smaller of nrI*nrJ
or ncI*ncJ, where
nrI is the number of rows in matrix A, nrJ is the number of
rows in matrix B,
ncI is the number of columns of A, and
ncJ is the number of columns in matrix B.
.br;Program statement:
.br.i 7;CALL #KRONK (SI, SJ, SK, nrI, ncI, nrJ, ncJ)
.br.i 7;CALL XKRONK (NRMI, NRMJ, NRMK, SI, SJ, SK, nrI, ncI, nrJ, ncJ)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit containing B;
 K is an integer designating the memory unit to contain C;
 nrI is an integer equal to the number of rows of A;
 ncI is an integer equal to the number of columns of A;
 nrJ is an integer equal to the number of rows of B; and
 ncJ is an integer equal to the number of columns of B.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>MATML\&
 This subroutine is used to perform matrix multiplication:
.br.i 7;AB#=#C
.br;Program statement:
.br.i 7;CALL #MATML (SI, SJ, SK, nr, nb, nc)
.br.i 7;CALL XMATML (NRMI, NRMJ, NRMK, SI, SJ, SK, nr, nb, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit containing B;
 K is an integer designating the memory unit containing C;
 nr is an integer equal to the number of rows of A and C;
 nb is an integer equal to the number of columns of A and rows of B; and
 nc is an integer equal to the number of columns of B and C.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>PRDDI\&
 This subroutine finds the product of the elements of the main diagonal
of a matrix and outputs the product to a FORTRAN constant, PR.
.br;Program statement:
.br.i 7;CALL #PRDDI (SI, n, PR)
.br.i 7;CALL XPRDDI (NRMI, SI, n, PR)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the matrix;
 n is an integer equal to the order of that matrix; and
 PR is a FORTRAN constant which will be equal to the
product of the elements across the major diagonal.
(Note - PR may be output as the (1,1) element of a matrix.)
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>RANK\&
 This subroutine determines the rank of a real matrix.
Note - the number of columns of the matrix must be ^&less\& than
the size of the memory units ^&minus\& one.
.br;Program statement:
.br.i 7;CALL #RANK (SI, SJ, nr, nc, RNK)
.br.i 7;CALL XRANK (NRMI, NCMI, NRMJ, SI, SJ, nr, nc, RNK)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the matrix;
 J is an integer designating the memory unit to contain a
temporary 'work' matrix
which may be used by the program;
 nr is an integer equal to the number of rows of the matrix;
 nc is an integer equal to the number of columns of the matrix
(must be ^&less\& than the size of the memory units ^&minus\& one); and
 RNK is a FORTRAN constant which on input equals the smallest eigenvalue
to be counted and on output contains the rank. It may be the (1,1) cell
of a memory unit Sk which is designated RNK. ^&When used repeatedly
remember to re-initialize RNK (i.e., set it to a small number).\&
A good initial value for RNK might be 0.0001.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>RXTX\&
 This subroutine premultiplies a matrix read in from cards by its transpose:
.br.i 7;A'A#=#B
.br;Note - (1)#Number of columns of A must be ^&less\& than the
size of the memory units.
.br;#######(2)#This program combines the functions of INPUT and XTX
as seen above and below.
.br;Program statement:
.br.i 7;CALL #RXTX (SI, nr, nc)
.br.i 7;CALL XRXTX (NRMI, SI, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit to contain B;
 nr is an integer equal to the number of rows of A (must be
^&identical to\& the number of rows as stated on the 'header
card'); and
 nc is an integer equal to the number of columns of A (must be
^&identical to\& the number of columns as stated on the 'header card').
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>SCAML\&
 This subroutine is used to multiply a matrix by a scalar quantity:
.br.i 7;aB#=#C
.br;Program statement:
.br.i 7;CALL #SCAML (a, SI, SJ, nr, nc)
.br.i 7;CALL XSCAML (NRMI, NRMJ, a, SI, SJ, nr, nc)
.LM +5.P -3, 0, 5.br;where:
 a is a real number. It may be a stored constant such as RNI. It
may be the (1,1) entry of a matrix stored in memory unit SH, in
which case SH is entered in the CALL statement at the location of
a. 'a' may be a real number in F format (with a decimal - e.g.,
0.25);
 I is an integer designating the memory unit containing B;
 J is an integer designating the memory unit to contain C;
 nr is an integer equal to the number of rows of B and C; and
 nc is an integer equal to the number of columns of B and C.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>SIMLN\&
 This subroutine is used to obtain the solution for simultaneous
linear equations of the form:
.br.i 7;XB#=#Y
.br;where X is an nr x nr matrix; Y is an nr x ns matrix;  and B is an
r x s matrix. X and Y are given and adjoined horizontally to
form matrix A:
.br.i 7;A#=#[X,Y],
.br;so that A is a matrix with nr rows and nc = nr#+#ns columns. Matrix
A is input into the subroutine. A solution for matrix B is obtained.
.br; The number of columns of A must be ^&less\& than the size of
the memory units.
.br;Program statement:
.br.i 7;CALL #SIMLN (SI, SJ, nr, nc)
.br.i 7;CALL XSIMLN (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit containing B;
 nr is an integer equal to the number of rows of A and B; and
 nc is an integer equal to the number of columns of A (must be
^&less\& than the size of the memory units).
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>SUB\&
 This subroutine is used to perform matrix subtraction:
.br;########A#-#B#=#C
.br;Program statement:
.br.i 7;CALL #SUB (SI, SJ, SK, nr, nc)
.br.i 7;CALL XSUB (NRMI, NRMJ, NRMK, SI, SJ, SK, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 J is an integer designating the memory unit containing matrix B;
 K is an integer designating the memory unit to contain matrix C;
 nr is an integer equal to the number of rows of the matrices; and
 nc is an integer equal to the number of columns of the matrices.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>TRACE\&
 This subroutine computes the trace of a square matrix, A.
.br;Program statement:
.br.i 7;CALL #TRACE (SI, n, SJ)
.br.i 7;CALL XTRACE (NRMI, NRMJ, SI, n, SJ)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 n is an integer equal to the order of A; and
 J is an integer designating the memory unit to contain the trace
as a 1 x 1 matrix. (Note - the trace may be output as a
FORTRAN constant.)
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>TRNSP\&
 This subroutine is used to transpose a matrix:
.br.i 7;Transpose of A = A'
.br;Program statement:
.br.i 7;CALL #TRNSP (SI, SJ, nr, nc)
.br.i 7;CALL XTRNSP (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit to contain A';
 nr is an integer equal to the number of rows of A and columns of
A'; and
 nc is an integer equal to the number of columns of A and rows of A'.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>XTX\&
 This subroutine premultiplies a matrix A by its transpose:
.br.i 7;A'A#=#B
.br;Note - number of columns of A must be ^&less\& than the
size of the memory units.
.br;Program statement:
.br.i 7;CALL #XTX (SI, SJ, nr, nc)
.br.i 7;CALL XXTX (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit to contain B;
 nr is an integer equal to the number of rows of A; and
 nc is an integer equal to the number of columns of A (must be
^&less\& than the size of the memory units).
.br; Note - B will be a matrix of order nc x nc.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>XXT\&
 This subroutine postmultiplies a matrix A by its transpose:
.br.i 7;AA'#=#B
.br;Note - number of rows of A must be ^&less\& than the
size of the memory units.
.br;Program statement:
.br.i 7;CALL #XXT (SI, SJ, nr, nc)
.br.i 7;CALL XXXT (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit to contain B;
 nr is an integer equal to the number of rows of A (must be
^&less\& than the size of the memory units); and
 nc is an integer equal to the number of columns of A.
.br; Note - B will be a matrix of order nr x nr.
.s 1
.end list
.subtitle Elementwise operations
.page
.tp 8.C; Elementwise Operations
.index Elementwise Operations
.list
.p 5, 0, 5.lm 0.le;^&Subroutine__<>ABS\&
 This subroutine is used to create a matrix containing the
absolute value of each of the entries of a given matrix:
.br.i 7;Abs[a(i,j)] = b(i,j)
.br;Program statement:
.br.i 7;CALL #ABS (SI, SJ, nr, nc)
.br.i 7;CALL XABS (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit to contain B;
 nr is an integer equal to the number of rows of the matrices; and
 nc is an integer equal to the number of columns of the matrices.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>ELEDI\&
 This subroutine is used to perform elementwise division
of entries in two matrices to create a third matrix:
.br.i 7;a(i,j)/b(i,j) = c(i,j)
.br;Matrices A and B must be the same order which will be the order
of C.
.br;Program statement:
.br.i 7;CALL #ELEDI (SI, SJ, SK, nr, nc, iflag)
.br.i 7;CALL XELEDI (NRMI, NRMJ, NRMK, SI, SJ, SK, nr, nc, iflag)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit containing B;
 K is an integer designating the memory unit to contain C;
 nr is an integer equal to the number of rows of the matrices;
 nc is an integer equal to the number of columns of the matrices; and
 iflag is an integer flag to tell the program what to do when
division by zero is attempted. If set to 0 the program will stop
if matrix B has
any zero elements. If set to 1 the program will insert
a zero into those elements of C for which a zero
element of B was found.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>ELEML\&
 This subroutine is used to perform elementwise multiplication
of the entries in two matrices to create a third matrix:
.br.i 7;a(i,j)xb(i,j) = c(i,j)
.br;Matrices A and B must be the same order which will be the order
of C. For example, a single matrix may be used as both A and B, thus
obtaining in C the squares of the entries in F.
.br;Program statement:
.br.i 7;CALL #ELEML (SI, SJ, SK, nr, nc)
.br.i 7;CALL XELEML (NRMI, NRMJ, NRMK, SI, SJ, SK, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit containing B;
 K is an integer designating the memory unit to contain C;
 nr is an integer equal to the number of rows of the matrices; and
 nc is an integer equal to the number of columns of the matrices.
.s 1
.tp 8.p 5, 0, 5.lm 0.le;^&Subroutine__<>RECIP\&
 This subroutine is used to create a matrix containing the
reciprocals of the entries of a given matrix:
.br.i 7;[1/a(i,j)]#=#b(i,j)
.br;Program statement:
.br.i 7;CALL #RECIP (SI, SJ, nr, nc, iflag)
.br.i 7;CALL XRECIP (NRMI, NRMJ, SI, SJ, nr, nc, iflag)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit to contain B;
 nr is an integer equal to the number of rows of the matrices; and
 iflag is an integer flag to tell the program what to do when
division by zero is attempted. If set to 0, the program will insert a
zero  when a corresponding zero element in A is found. If set
to 1, processing is to stop when an entry of zero is found in A.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>SQRT\&
 This subroutine is used to create a matrix containing the
square roots of the elements in a given matrix:
.br.i 7;Square root of [a(i,j)] = b(i,j)
.br;Program statement:
.br.i 7;CALL #SQRT (SI, SJ, nr, nc, eps)
.br.i 7;CALL XSQRT (NRMI, NRMJ, SI, SJ, nr, nc, eps)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit to contain B;
 nr is an integer equal to the number of rows of the matrices;
 nc is an integer equal to the number of columns of the matrices; and
 eps is a FORTRAN constant which is negative and
small in absolute value. If an entry in A is negative but less
than eps in absolute value, this entry is converted to zero in B.
If an entry in A is more negative than eps, processing is stopped.
A possible value might be -0.001. Note that in computing, an expected
value of zero might be slightly less than zero (i.e., negative) due
to rounding.
.end list.s 1
.index Data Handling Operations
.page.tp 8.C; Data Handling Operations
.subtitle Data Handling Operations
.list.p 5, 0, 5.lm 0.le;^&Subroutine__<>COPY\&
 This subroutine is used to copy a matrix from one memory unit to
another.
.br;Program statement:
.br.i 7;CALL #COPY (SI, SJ, nr, nc)
.br.i 7;CALL XCOPY (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the matrix;
 J is an integer designating the memory unit to contain the matrix;
 nr is an integer equal to the number of rows of the matrix; and
 nc is an integer equal to the number of columns of the matrix.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>DIAG\&
 This subroutine is used to create a diagonal matrix D containing
the diagonal entries of a square matrix A.
.br;Program statement:
.br.i 7;CALL #DIAG (SI, SJ, n)
.br.i 7;CALL XDIAG (NRMI, NRMJ, SI, SJ, n)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing A;
 J is an integer designating the memory unit to contain D; and
 n is an integer equal to the number of rows and columns of A and D.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>HORIZ\&
 This subroutine is used to horizontally 'join' two matrices,
X and Y, together to form a new 'super' matrix A. Matrices X and Y both have
nr rows.
.br.i 7;A#=#[X,Y]
.br;Let X have 'x' columns and Y have 'y' columns; A will have
c#=#x#+#y columns (the first x columns from matrix X and the last
y columns from matrix Y).
.br;Program statement:
.br.i 7;CALL #HORIZ (SI, SJ, SK, nr, nx, ny)
.br.i 7;CALL XHORIZ (NRMI, NRMJ, NRMK, SI, SJ, SK, nr, nx, ny)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing X;
 J is an integer designating the memory unit containing Y;
 K is an integer designating the memory unit to contain A;
 nr is an integer equal to the number of rows of each matrix;
 nx is an integer equal to the number of columns of X; and
 ny is an integer equal to the number of columns of Y.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>PARTT\&
 This subroutine is used to select a rectangular section or
partition of a matrix A and copy this section into a new matrix
B. The beginning row of the section in matrix A is 'nrb'
and the ending row is 'nre'. The beginning column is 'ncb' and the
ending column is 'nce'.
.br;Program statement:
.br.i 7;CALL #PARTT (SI, SJ, nrb, nre, ncb, nce)
.br.i 7;CALL XPARTT (NRMI, NRMJ, SI, SJ, nrb, nre, ncb, nce)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 J is an integer designating the memory unit to contain matrix B;
 nrb is an integer equal to the beginning row number of the section;
 nre is an integer equal to the ending row number of the section;
 ncb is an integer equal to the beginning column number of the section; and
 nce is an integer equal to the ending column number of the section.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>RO2DI\&
 This subroutine is used to create a diagonal matrix D whose
elements along the diagonal are entries from the
first row of a second matrix A.
.br;Program statement:
.br.i 7;CALL #RO2DI (SI, SJ, n)
.br.i 7;CALL XRO2DI (NRMI, NRMJ, SI, SJ, n)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing matrix A;
 J is an integer designating the memory unit to contain D; and
 n is an integer equal to the order of A.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>RO2MT\&
 This subroutine is used to create a matrix B for which every row is
identical to the first row  of a given matrix A.
The first row of matrix A is copied nr times to form a matrix B.
This operation is the same as the matrix product:
.br.i 7;(1)A#=#B
.br;where (1) is a column vector with nr entries of unity.
.br;Program statement:
.br.i 7;CALL #RO2MT (SI, SJ, nr, nc)
.br.i 7;CALL XRO2MT (NRMI, NRMJ, SI, SJ, nr, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit
containing row vector/matrix A;
 J is an integer designating the memory unit
to contain matrix B;
 nr is an integer equal to the number of rows of B; and
 nc is an integer equal to the number of columns of A and B.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>VRTCL\&
 Given two matrices X and Y, each having nc columns, a new matrix
A is formed by adjoining matrices X and Y vertically:
.br.i 7;A#=###X
.br.i 7;######Y
.br;Let X have 'x' rows and Y have 'y' rows; A will have r#=#x#+#y
rows (the first x rows of A will be from X and the last y rows
of A will be from Y).
.br;Program statement:
.br.i 7;CALL #VRTCL (SI, SJ, SK, nx, ny, nc)
.br.i 7;CALL XVRTCL (NRMI, NRMJ, NRMK, SI, SJ, SK, nx, ny, nc)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing X;
 J is an integer designating the memory unit containing Y;
 K is an integer designating the memory unit to contain A;
 x is an integer equal to the number of rows of X;
 y is an integer equal to the number of rows of Y; and
 nc is an integer equal to the number of columns of the matrices.
.s 1
.end list
.p 5, 0, 5.lm 0
.subtitle Statistical Programs
.page.tp 8.C; Statistical Operations
.index Statistical Operations
.s 1.tp 8.C; A.##Factor Analytic and Correlational Methods
.index Factor Analytic Methods
.index Correlational Methods
.s 1.list.p 5, 0, 5.lm 0.le;^&Subroutine__<>DAPPR\&
 This subroutine is used to obliquely rotate a factor
loading matrix, using either a 'mechanical' rotator (termed artificial
personal probability) or a rotation 'directed' by the user (i.e.,
input is in the form of probability of being in the hyperplane).
.br;Program statement:
.br.i 7;CALL #DAPPR (SI, SJ, SK, SL, SM, SN, SO, SP, SQ, nat, nf,
.br.i 6;1 mcase, mpj, mapp, mprin, pcon, wcon, coslt, ncyclt)
.br.i 7;CALL XDAPPR (NRMI, NRMJ, NRMK, NRML, NRMM, NRMN, NRMO,
.br.i 6;1 NRMP, NRMQ, SI, SJ, SK, SL, SM, SN, SO, SP, SQ, nat, nf,
.br.i 6;2 mcase, mpj, mapp, mprin, pcon, wcon, coslt, ncyclt)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the original
factor matrix;
 J is an integer designating the memory unit to contain the N' matrix
of hyperplane normals;
 K is an integer designating the memory unit containing matrix
P during solution and converted to B for output (see MPJ);
 L is an integer designating the memory unit to contain APP
(see note concerning mapp);
 M is an integer designating the memory unit containing the inverse
of NN' and will contain PHI for output;
 N, O, P, and Q are integers designating some 'scratch' memory units
(i.e., memory units that the computer can work with to obtain an answer);
 nat is the number of attributes (variables);
 nf is the number of factors;
 mcase is an integer flag for APP function. Set mcase#=#1 for one
sided function (e.g., you expect the factors to have a positive
manifold). Set mcase#=#2 for a two sided function (e.g., factors
will correlate both positively &a&n&d negatively with one
another);
 mpj is an integer flag for initial weights hypothesized. Set mpj#=#0
for initial weights to be obtained by a VARIMAX rotation. Set
mpj#=#1 for initial hypothesis factor weights to be input in SK;
 mapp is an integer flag concerning iteration of APP. Set mapp#=#0
for APP iteration. Set mapp#=#1 for a fixed APP as input to SL;
 mprin is an integer flag concerning the printing of technical output. Set
mprin#=#0 for printed output. Set mprin#=#1 for printing matrices
APP and P on each cycle;
 pcon is a power constant in APP function (set it to 10.0);
 wcon is the proportion of mean absolute factor weight for APP
(set it to 0.5);
 coslt is a limit for COS between successive trial normals in test
for convergence (set it to 0.99999); and
 ncyclt is the maximum number of iteration cycles (set it to 20).
.s 1; To fit a hypothetical matrix, the input to APP is the probability
of being in the hyperplane. This is another way of saying the probability
of ^&NOT\& loading on the factor.  If you have a matrix of probabilities
of loading of the factor, then subract them from 1.0. Let MAPP#=#1 and
set MPJ#=#1.
.s 1
.tp 9
.p 5, 0, 5.lm 0.le;^&Subroutine__<>FAHIR\&
 This subroutine does factor analysis using  the highest covariance
(or correlation if the input matrix is a correlation matrix)
as communality estimate.
.br;Program statement:
.br.i 7;CALL #FAHIR (SI, SJ, SK, SL, nat, nf)
.br.i 7;CALL XFAHIR (NRMI, NRMJ, NRMK, NRML, SI, SJ, SK, SL, nat, nf)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the covariance
(or correlation) matrix;
 J is an integer designating the memory unit to contain the
covariance (or correlation) matrix with the highest covariances
(or correlations) on the diagonal;
 K is an integer designating the memory unit to contain the factor
matrix;
 L is an integer designating the memory unit to contain the
communalities for each factor per variable;
 nat is the number of attributes (variables); and
 nf is the number of factors desired. If nf is greater than
the number of positive eigenvalues, nf will be changed. Therefore
nf should &n&o&t be input as a number, but as a variable (see
FORTRAN constants).
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>FAWMV\&
 This subroutine does factor analysis using  the multiple
variance (or correlation if the input matrix is a correlation matrix)
as communality estimate. If the matrix is singular the highest
covariance is used as the communality estimate (see FAHIR above).
.br;Program statement:
.br.i 7;CALL #FAWMV (SI, SJ, SK, SL, nat, nf)
.br.i 7;CALL XFAWMV (NRMI, NRMJ, NRMK, NRML, SI, SJ, SK, SL, nat, nf)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the covariance
(or correlation) matrix;
 J is an integer designating the memory unit to contain the
covariance (or correlation) matrix with the multiple variances
(or correlations) on the diagonal;
 K is an integer designating the memory unit to contain the factor
matrix;
 L is an integer designating the memory unit to contain the
communalities for each factor per variable;
 nat is the number of attributes (variables); and
 nf is the number of factors desired. If nf is greater than
the number of positive eigenvalues, nf will be changed. Therefore
nf should &n&o&t be input as a number, but as a variable (see
FORTRAN constants).
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>ITPFA\&
 This subroutine is used to compute communalities by the iterated
principal components method.
.br;Program statement:
.br.i 7;CALL #ITPFA (SI, SJ, SK, SL, SM, nat, nf)
.br.i 7;CALL XITPFA (NRMI, NRMJ, NRMK, NRML, NRMM, SI, SJ, SK, SL,
.br.i 6;2  SM, nat, nf)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the input
covariance (or correlation) matrix;
 J is an integer designating the memory unit to contain the factor
matrix;
 K and L are integers designating temporary 'work' matrices for
the computer;
 M is an integer designating the memory unit to contain the
covariance (or correlation) matrix with the communality estimates
on the major diagonal;
 nat is an integer equal to the number of attributes (variables); and
 nf is an integer equal to the number of factors.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>LSHYP\&
 This subroutine is used to rotate a factor matrix to form a best
(least squares) hyperplane fit to a matrix selected by the user.
.br;Program statement:
.br.i 7;CALL #LSHYP (SI, SJ, SK, SL, SM, SN, nr, nc, iflag)
.br.i 7;CALL XLSHYP (NRMI, NRMJ, NRMK, NRML, NRMM, NRMN, SI, SJ,
.br.i 6;2 SK, SL, SM, SN, nr, nc, iflag)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing
the input factor matrix;
 J is an integer designating the memory unit containing the
selection matrix (all 0s or 1s - 0 if in the factor and 1 if not);
 K is an integer designating the memory unit to contain
the normal matrix (transposed);
 L, M, and N are integers designating temporary 'work' memory units to be
used by the computer;
 nr is an integer equal to the number of rows of both SI and SJ;
 nc is an integer equal to the number of columns of both SI and SJ; and
 iflag is an integer equal to 0 if the user wants to skip intermediate
technical results or 1 to print out intermediate results.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>MISNR\&
 This subroutine is used to compute a correlation matrix (when
some missing data exists).
.br;Program statement:
.br.i 7;CALL #MISNR (SI, SJ, SK, SL, SM, SN, SO, SP, SQ, SR, ns,
.br.i 6;2 nat, iopt, ione)
.br.i 7;CALL XMISNR (NRMI, NRMJ, NRMK, NRML, NRMM, NRMN, NRMO, NRMP,
.br.i 6;2 NRMQ, NRMR, SI, SJ, SK, SL, SM, SN, SO, SP, SQ, SR, ns,
.br.i 6;3 nat, iopt, ione)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the raw data;
 J is an integer designating the memory unit to contain the means
of the variables (if options 5 or 6 are used, this matrix has the
means for row variables when there is data for this
variable and the column variable);
 K is an integer designating the memory unit to contain the variances
of the variables (if options 6 or 8 are used, this matrix has the
means for column variables when there is data for this
variable and the row variable);
 L#is an integer designating the memory unit to contain the
covariance matrix;
 M#is an integer designating the memory unit to contain the
correlation matrix;
 N is an integer designating the memory unit containing
information on how missing data is
stored;
 O, P, and Q  are integers designating memory units containing
matrices the computer can use to store intermediate results;
 R#is an integer designating the memory unit to contain the
sample sizes for pairwise correlations;
 ns is an integer describing the number of subjects in the
data (number of useful rows in SI);
 nat is an integer describing the number of variables (attributes)
in the data (number of columns in SI);
 iopt is an integer flag describing numerous options on handling
missing data:
.nojustify.nofill
  iopt    result
   1      Compute vector of means and sample sizes only.
   2      Compute correlation, etc. matrices but do &n&o&t check for
           missing  data  (will give incorrect results if missing
           data is present).
   3      Replace missing data by mean.
   4      Delete  all  of  the  subject's  data  if  there is any
           missing data.
   5      Compute   covariances   based  on  available  pairs  of
           data.   Means  and covariances will be based on avail-
           able pairwise  data  for that pair of variables only.
           Correlations  will  be based on these covariances and
           variances from the diagonal of the covariance matrix.
    6     Compute pairwise covariances as in 5 above.   Estimates
           of variances  (for correlations) are based on pairwise
           data for that pair of variables only.
    7     Covariances are based  on available pairs, however the
           full data means will be utilized.   Correlations will
           be based on full data variances (diagonal of
           covariance matrix).
    8     Covariance matrix computed as in 7 above.  Correlations
           use  the  pairwise  data  variances  (as  in  option 6
           above).
.fill.justify
.SUBTITLE Monte Carlo Programs
 ione is an integer containing either -1, 0, or +1.  The integer
is added to the sample size (N) in the denominator of the
variances and covariances. For example, if -1 is input the variance will
be computed by (Sum#of#Squares)/(N#-#1).  This will result in the unbiased
variance estimate.  When ione is 0 the result will be the maximum
likelihood estimate. When ione is +1 the result is a minimum error
estimate.
.s 1.lm 3;[Note: As a special option (only for the most advanced
users) one can generate cross product and normed cross product
matrices. That is, occassionally it is useful ^&not\& to subtract
the mean in computations for either the covariances or the correlations.
The covariances will be cross products and the correlations are called
normed (i.e., made to unit length) cross products. To use this option,
place immediately after the "COMMON/B/I1" statement a new statement
"COMMON/KMISNR/KMISNR", then somewhere before the call to MISNR put
in the statement ">KMISNR = 1".  In order to compute regular
correlations again set "KMISNR = 0" (i.e., to again subtract
the mean in the calculations).
.lm 0.S 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>VARMX\&
 This subroutine is used to rotate a factor matrix
orthogonally to the VARIMAX criterion.
.br;Program statement:
.br.i 7;CALL #VARMX (SI, SJ, SK, nat, nf)
.br.i 7;CALL XVARMX (NRMI, NRMJ, NCMJ, SI, SJ, nat, nf, SK, mkraw)
.lm +5.p -3, 0, 5.br;where:
 I is an integer designating the memory unit containing the input
factor matrix;
 J is an integer designating the memory unit to contain the factor
loading matrix;
 K is an integer designating a temporary 'work' ^&vector\& for
the computer;
 nat is an integer equal to the number of attributes (variables);
 nf is an integer equal to the number of factors; and
 mkraw is an integer flag. If set to 0 a raw (unweighted)
solution will be done. If set to 1 a normalized solution
is performed.
.END LIST
[Note - the 'X' version is slightly different in
form from the 'non-X' version.]
.tp 8.C;B.##Monte Carlo Programs
.SUBTITLE Discriminant Analysis
.S 1.index Monte Carlo Programs
.lm 10.rm -10
Note - A full
description of the following Monte Carlo programs will
not be given. For more detailed information see FORMAL.DOC.
.lm 0.rm +10
.s 1.list.p 5, 0, 5.lm 0.le;^&Subroutine__<>RANDQ\&
 This subroutine is used to generate a sample SSCP (Sum of Squares and Cross
Products) matrix and a mean vector.
The data has a
multivariate normal distribution given a population mean and a covariance
matrix.
.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>RNDCR\&
 This program is used to compute matrices containing means, standard deviations,
covariances and correlations from the matrices of products
and sums.
.s 1
.p 5, 0, 5.lm 0.le;^&Subroutine__<>RNDVC\&
 This program is used to generate a vector of random normal deviates,
mean = 0 and standard deviation = 1, randomly sorted.
.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>TSAMX\&
 This program is used to generate a vector of random normal deviates
with a given population mean vector and a covariance matrix.
.end list.s 1.p 5, 0, 5.lm 0
.s 1.TP 9.tp 8.C; C.##Discriminant Analysis
.index Discriminant Analysis
Note - A full
description of the following Monte Carlo programs will
not be given. For more detailed information see FORMAL.DOC.
.s 1.p 5, 0, 5.lm 0;^&Subroutine__<>DISCR\&
 This subroutine is used to do a discriminant analysis. Input
will be the hypothesis effect and denominator effect (error)
Sum of Squares and Cross Products (SSCP). Output will be Phi,
Lambda, Bartlett's V statistic, eigen roots and vectors of the
total SSCP matrix, weight matrix and group means for the
discriminant function.
.s 1.tp 8.tp 8.C;D.##Analysis of Variance
.index Analysis of Variance
.s 1.p 5, 0, 5.lm 0;^&Subroutine__<>BALANO\&
 This subroutine is a general analysis of variance program applicable
to a wide range of balanced designs.  In the case of designs
with a replication factor, BALANO allows inequality in the number
of replications in each cell. If the number of replications
is equal or proportional, the analysis is handled by least
squares (weighted means). If the number of replications is
not proportional, then an unweighted means analysis is performed.
This is an approximation to the least squares solution.
 BALANO accepts some designs that are not completely crossed, namely
those nested designs in which all main factors are balanced. Hence
hierarchical designs are allowed. Repeated measure designs are
allowed as well. In these designs the replication factor is not
nested in all of the other factors.
.br;Program statement:
.br.i 7;CALL BALANO (NRMI, NRMJ, NRMK, SI, SJ, SK, SL, NRI, NCJ,
.br.i 6;1 nf, ndep, xmis, iflag1, iflag2, iflag3)
.lm +5.p -3 0 5.br;where:
 I is an integer designating the memory unit to contain the data and
level numbers to be input to BALANO.  Each observation (row of data)
input to BALANO must be identified by a number for each factor
including the replication factor.  These numbers represent the levels
of the corresponding factors and must precede the dependent variables.
In the output produced by BALANO, each factor is given a unique letter
name beginning with A.  Thus the first column of the data matrix
corresponds to the levels of factor A which is described in the first
row of the factor specification matrix, SJ (see below).  Each
additional factor is given the next letter in the alphabet and a
corresponding row in the factor specification matrix.  The dependent
variables follow the factor levels on each row in the data matrix
and are numbered one through the total number of dependent variables
in the output of the program.  For example, a row in SI contains the
following data:   9.  8.  7.  6.  5.   Assuming that this design has
three factors and two dependent variables then 9, 8, and 7 are the levels
for the factors A, B, and C respectively.  6 and 5 are dependent variables
1 and 2 respectively.  It does not matter what order the rows are in, as
long as the dependent variables correspond to the levels input in the
same row in matrix SI.
 J is an integer designating the memory unit to contain the factor
specification matrix.  Each row in this matrix corresponds to a
factor in the order in which the factors appear in the data matrix
SI (i.e. the first row in the factor specification matrix corresponds
to the first column in the data matrix, etc.).  There must be one
row in the matrix SJ for each factor.  Each column in the
factor specification matrix corresponds to the following parameters:
.TP 8.lm +5.br;Column	Description
.br;##1	#	0 if it is the fixed factor.
.br;#	#	1 if it is the random factor.
.s 1;##2	#	0 if it is not the replication factor.
.br;#	#	1 if it is the replication factor.
.s 1;#3-11	#	Factors in which this factor is nested.
.lm -5.s 1;All elements in the factor specification matrix which are
not used must be set to zero.
 K is an integer designating a one dimensional 'scratch' memory unit that has
been dimensioned as SK(NRMK).  If the dimension NRMK is too small, BALANO
will output a minimum required value for you.
 L is an integer designating a vector that contains
the number of levels for each factor, i.e. SL(1) contains the number of
levels of the first factor, SL(2) contains the number of levels of the
second factor, etc.  All locations in SL not used are set to zero.  This
memory unit must be dimensioned as SL(10).
 NRI is an integer equal to the number of rows of the data matrix SI.
 NCJ is an integer equal to the number of columns of the factor
specification matrix SJ.  This number need only be large enough so
that all non-zero values are within the matrix.
 nf is the number of factors including the replication factor (if there is
one).  Maximum = 10.
 ndep is the number of dependent variables.
 xmis is the code for missing data for the dependent
variable in matrix SI.  If there is no
missing data, then xmis should be set to a value not found in any
of the data which is input to the data matrix SI.
 iflag1 is +1 if the user desires to do an unweighted means analysis even
though proportional cell frequencies could be found.
 iflag2 is +1 to suppress printing of all means
.lm +7;-1 to suppress printing of all interaction means
.br;-2 to suppress printing of all level means.
.lm -7; iflag3 is the factor number for which printing of interaction means is to
be suppressed (only one factor number allowed).
.lm 0.p 5 0 5.s 1
 A numerical example from Winer, page 376 (table 7.8-3), is
illustrated here using BALANO.
TEST.FOR is the calling program that you want to run.
.nofill.nojustify
.s 1
 .EX TEST.FOR,FORMAL.REL/SEARCH,REL:IMSL/SEARCH
.s 1
 The program TEST.FOR for this example is listed below.
.s 1
      IMPLICIT DOUBLE PRECISION(A-H,O-Z)
      DIMENSION S1(36,4),S2(3,3),S3(147),S4(10)
      CALL IOPUT('BALDAT.DAT','BALOUT.DAT',3)
      CALL XINPUT(36,S1)
      CALL XINPUT (3,S2)
      CALL XINPUT(10,S4)
      CALL BALANO(36,3,147,S1,S2,S3,S4,
     1 36,3,3,1,999.,0,0,0)
      STOP
      END
.s 1
 The data file (BALDAT.DAT in line 3 of the program above) to be input
to BALANO is listed below:
.s 1
00360004(4F3.0)
  1  1  1  3
  1  2  1  6
  1  3  1  9
  1  1  2  6
  1  2  2 10
  1  3  2 14
  1  1  3 10
  1  2  3 15
  1  3  3 18
  2  1  4  8 (e.g., factor A - level 2; factor B - level 1; factor
  2  2  4 12        C - level 4; score on dependent variable is 8)
  2  3  4 16
  2  1  5  3
  2  2  5  5
  2  3  5  8
  2  1  6  1
  2  2  6  3
  2  3  6  8
  2  1  7 12
  2  2  7 18
  2  3  7 26
  2  1  8  9
  2  2  8 10
  2  3  8 18
  3  1  9 10
  3  2  9 22
  3  3  9 16
  3  1 10  3
  3  2 10 15
  3  3 10  8
  3  1 11  7
  3  2 11 16
  3  3 11 10
  3  1 12  5
  3  2 12 20
  3  3 12 12
00030003(3F3.0)
  0  0  0 (factor A is a fixed factor)
  0  0  0 (factor B is a fixed factor)
  1  1  1 (factor C, the replication factor, is random and nested in
00100001(F3.0)                                             factor A)
  3 (factor A has 3 levels)
  3 (factor B has 3 levels)
 12 (the subjects factor C has 12 levels or subjects)
  0
  0 (Note: these were set to zero)
  0
  0
  0
  0
  0

.fill.justify;  Part of the output file that BALANO will print for you
(BALOUT.DAT in line 3
of the program above) is listed below.
.nofill.nojustify
SOURCE  DEG OF FREEDOM  SUM OF SQUARES   MEAN SQUARE    F RATIO  PROB.
         NUM     DEN

 A         2       9    0.22933333E+02  0.11466667E+02  0.1685 0.8476
 C         9            0.61262222E+03  0.68069136E+02
 B         2      18    0.36505556E+03  0.18252778E+03 84.0759 0.0000
 AXB       4      18    0.19586667E+03  0.48966667E+02 22.5550 0.0000
 BXC      18            0.39077778E+02  0.21709877E+01

FACTOR C IS THE REPLICATION FACTOR AND C HAS AN UNEQUAL NUMBER OF
LEVELS FOR EACH COMBINATION OF LEVELS OF THE FACTORS IN WHICH IT IS
NESTED.  HOWEVER THE NUMBER OF LEVELS ARE PROPORTIONAL AND HENCE THE
DESIGN IS BALANCED.  THE ANALYSIS OF VARIANCE IS EXACT EXCEPT FOR
TRUNCATION AND ROUNDING ERRORS.
.fill.justify
.page
.subtitle Advanced Techniques
.tp 8.C;Advanced Techniques
.index Advanced Techniques
.LIST.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>IOPUT\&
 This subroutine will allow the user to write to any file
(including the line printer or tape) and
read the input data from any file (including the card reader or tape).
.br;Program statement:
.i 7;CALL IOPUT('input string', 'output string', iflag)
.lm +5.p -3, 0, 5.br;where:
 'input string' is the name of the file containing input
data. The form of this string can be 'dev:filenm.ext[p,pn,sfd...]'
(the most common form of this string will be 'filenm.ext').  When
the user elects not to use this subroutine or uses option 2 or 3
the program will read its data  from a file called FRMLIN.DAT.
 'output string' is the name of the file to contain the output
from FORMAL.  The form of this string is identical to 'input
string' above.  When the user does not use this subroutine or
uses option 1, the filenm.ext will default to FRMLOT.DAT; and
 iflag is an integer flag to indicate what actions this program
will take:
.nojustify.nofill
               1 - only open the input file (output will still be
                    FRMLOT.DAT).
               2 - only open the output file (input will still be
                    FRMLIN.DAT).
               3 - open both the input and output files.
.justify.fill.lm 0.p 5,0,5
 By use of this subroutine one can read a data file that is on
disk rather than using a deck of cards.  In this
case leave out the data and the $DATA cards (e.g., cards 48 through
54 in the Card Pack for Example) and replace them with a
'$EXECUTE' card (beginning in column 1).
In the above subroutine, prefix the input data disk file name with 'DSK:'.
For example, if there were a data file called 'FILE.DAT' in the user area
_<1234,567_> and you wanted the output to print on the line printer
as usual, insert the following card before the first INPUT command:
.br.i 7;CALL IOPUT ('DSK:FILE.DAT_<1234,546_>','FRMLOT.DAT',1)
.br;Note:  if the user area is your own you may omit the ppn numbers and
their brackets.
.s 1.p 5, 0, 5.lm 0.le;^&Subroutine__<>TINPT\&
 This subroutine will allow the user to input data from any
data set or new file name.
.br;Program statement:
.i 7;CALL #TINPT ('input string', SI)
.i 7;CALL XTINPT (NRMI, 'input string', SI)
.lm +5.p -3, 0, 5.br;where:
 'input string' is the name of the file containing input
data; the form of this string can be 'dev:filenm.ext[p,pn,sfd...]'
(the most common form of this string will be 'filenm.ext'); and
 I is an integer designating the memory unit to contain the
new input matrix.
.end list.p 5, 0, 5
.lm 0
 The form of the 'input string' is the same as in IOPUT above.
Before the use of this program the user must have the device
name assigned to unit 25.  That is, the user must have made
an open similar to:
.index <ASSIGN statement
.subtitle Advanced Techniques/Terminal Usage/Debugging Aids
.i 6;_.ASS DSK 25
.br;within the TOPS10 calls or at the terminal (other more
advanced methods are possible by use of the logical device
name and a COMMON statement).
.subtitle Use at Terminal
.s 1.tp 8.tp 8.C;Use at Terminal
.index Use at Terminal
.s 1
 To use FORMAL from the terminal
one must put the program in one file, which has an extension
of FOR (e.g., HWTEST.FOR), and the input data in a second file.
The input data file can have any name but the computer will default to
'FRMLIN.DAT' if the user does not provide a input file name
(to do this see IOPUT above). The output will be in a third file, again
with any name as defined in IOPUT above or with the default value of
'FRMLOT.DAT'.
 To run FORMAL from the terminal either type the following into
a file (e.g., HWTEST.CTL) or type it into the terminal as you sit there:
.nofill.nojustify.lm 6
_.ASS DSK 2    (if the user wants to input data from the terminal
                instead of the the disk change DSK above to TTY)
_.ASS DSK 3    (if  the   user  wants  to  have   the  output  go
                automatically to the line printer do not enter
                this line; if the user wants to have the  output
                automatically  appear  at  the  terminal  change
                'DSK 3' to 'TTY 3')
_.EX progname.FOR,FORMAL.REL[1413,546]/SEARCH
              (if the user is running BALANO, insert the
                following after SEARCH: ".../SEARCH,REL:IMSL.REL/SEARCH")
_.Q progname.FOR,'input.file','output.file'
              (if the  _.ASS DSK 2 line is changed to TTY 2 there
                will   be   no  input  file  so  leave  out  the
                'input.file',  if   the _.ASS DSK 3  statement is
                not present or changed to TTY 3 there will be no
                'output.fil'  so leave  'output.fil' out of this
                'print' command)
.justify.fill.lm 0
.br;where progname.FOR is the name of the FORMAL program (e.g.,
HWTEST.FOR).
 If the user has created a file as above (e.g., HWTEST.CTL), to run
it type:
.i 6;_.<>SUBMIT HWTEST.CTL
.br;in order to have the program run at batch and submitted automatically.
Otherwise type:
.i 6;_.<>DO HWTEST.CTL
.br;to have the program run semi-automatically (in front of the user
at the terminal).
.subtitle Advanced Debugging Aids
.s 1.tp 8.C; Advanced Debugging Aids
.index Advanced Debugging Aids
.s 1
 Throughout FORMAL every attempt was made to anticipate and minimize
possible user errors and lessen their effect if made.
Nevertheless, errors will occur.  When FORMAL finds an error the
program will attempt to describe what the error is and where it is
found. In describing the location of the error three variables are
frequently printed out: call statement number, subroutine number, and
depth.
 The call statement number, >ipgm in the program, is the current number of
.index Call Statement Number
FORMAL call statements made from the user's program. That is, if
an error was seen in the 25th call to FORMAL, the call statement
number will be 25.
 The subroutine number, >isub in the program, is the number of subroutines
.index Subroutine Statement Number
used indirectly since the last call in the user's program.  That is,
most programs call other programs and isub is the number of such calls.
.index Depth
 Depth, >izncr in the program, will be 0 at all FORMAL calls from
the user's program; it will be 1 at all FORMAL calls made one
subroutine away from the main program; it will be 2 at all FORMAL calls
made two subroutines away from the main program, etc.
.s 1
 For example, let us suppose that the 25th call were to INVRS and
the input matrix was singular.  E.g., let us suppose that in the
Example Card Pack one of the variables had zero variance. Then:
.nofill.nojustify.s 1
A call to INVRS will call XINVRS,
XINVRS calls XDIMCH then returns to XINVRS,
XINVRS calls XDIMCH then returns to XINVRS,
XINVRS calls XDIMCH then returns to XINVRS,
XINVRS calls XDIMCH then returns to XINVRS,
XINVRS calls QMINVZ,
QMINVZ calls XDIMCH then returns to QMINVZ,
QMINVZ calls XDIMCH then returns to QMINVZ,
QMINVZ calls XDIMCH then returns to QMINVZ, and finally
QMINVZ calls QWRGDM.
.s 1
The following output would be seen:
 *    *    *    *    *    T  I  L  T    *    *    *    *    *

* * * * * THE MATRIX PASSED WAS SINGULAR NO INVERSE WAS POSSIBLE.

 FATAL ERROR IN THE INVRS  PROGRAM.  THIS WAS THE   25-TH CALL
 MADE BY YOU TO THE FORMAL LIBRARY.
 ACTUALLY   10 MORE CALLS WERE MADE TO THE FORMAL PACKAGE
 (INTERNALLY), CURRENT DEPTH:    3

* * * * * PROCESSING MUST TERMINATE PREMATURELY * * * * *
.s 1
.fill.justify.lm 0
 You may note that ten subroutine calls were made (internally)
by FORMAL subroutines: once to XINVRS, QMINVZ, and   QWRGDM and
seven times to XDIMCH.
The depth is three when FORMAL calls XINVRS. Then XINVRS eventually
calls QMINVZ and QMINVZ calls QWRGDM which describes the
error.
.page.do index
 is three when FORMAL calls XINVRS. Then XINVRS eventually
calls QMINVZ and QMINVZ calls QWRGDM which describes the
error.
.page.do index
L calls XINVRS. Then XINVRS eventually
calls QMINVZ and QMINVZ calls QWRGDM which describes the
error.
.page.do index
 is three when FORMAL calls XINVRS. Then XINVRS eventually
calls QMINVZ and QMINVZ calls QWRGDM which describes the
error.
.page.do index