!This script performs an orthogonal axes rotation
!to comply with the Kaiser (1958) simplicity criterion
!(cf McDonald, Factor analysis and related methods,
!p. 86).  The customary Kaiser normalization is included.
!Thus, MX can do exploratory factor analysis.
!
!This rotation script permits exploration of the factor structure.
!If the output, a rotated factor pattern is interpretable, and if
!it has meaning with respect to the investigator's research
!objectives, the investigator is advised to test the robustness
!of the rotated factor model either on a unused portion of
!his/her original data, or in a new cross-validation
!sample. MX is also suitable for such a second confirmatory
!factor analysis run.
!
!The script is divided into four groups:
!The first calc group performs the Kaiser normalization
!of the unrotated input matrix, the second finds the rotation
!matrix to optimize the simplicity criterion and the
!third calc group "de-normalizes" the formerly normalized
!rotated pattern matrix.  Original communalities are
!restored. 
!
!A fourth group constrains elements of the rotation
!matrix a to remain greater than -1 and less than 1.
!This has the effect of keeping axes orthogonal.
!
!In #define statements, change nv and nf to the
!number of variables and factors for your input
!unrotated factor pattern.
!
!The varimax rotated matrix
!z is in the output for the third group.  Click on
!group 3 to see it in Job Manager.  Variable labels for the
!Varimax rotated factor pattern z can
!be supplied in group 1 as shown.
!Remember to comment out test data labels
!you are not using in group 3.
!
!You will want to comment out the test data below,
!and read in the unrotated factor pattern matrix
!of your choice from the desired path and file,
!as shown in group 1.
!
!You have optional write to disk of rotated
!Varimax factor pattern z in group 3.
!Remove the comment ! and choose your
!file name and path, as shown.
!
!Choice of a factor rotation is an esthetic one.  If you
!don't "like" Varimax try Quartimax and vice-versa.
!
!Recall that there are from several to many equally
!valid Varimax rotations, depending upon start values.
!Any one or more axes may be located at a position
!+ or - 90 degrees from that of a previous run.  This
!makes no difference in interpretation, since you can
!"reflect" one or more factors by multiplying all
!loadings on a given factor  by -1. This often
!assists interpretation.  The absolute values
!in rotated factor pattern z will always be the
!same after a valid run. To get z mtx, go to Grp 3
!and click on Mtx z.  You can activate labels as shown
!in test examples. To make things easier, variable
!labeling is done at the top of the program
!
!In the program below, choose any one
!element of the rotation matrix a and assign start
!values of -.3 to .7.  You can pick one out of a
!hat.  Several examples (commented out) are shown.
!This usually nudges a P III 600 mhz
!into convergence in less than .7 second.
!
!If you get "optimization failed: constraint error!"
!try different start values.
!
!Try several runs with different start values,
!and jot down the value
!of the Kaiser Simplicity criterion each time.
!You should get the exact same value in several
!valid runs, with no or  minimal warnings about
!convergence. It pops up in the gray results panel
!next to USER.
!
!If you get any complaints about convergence,
!assign different start values to different elements
!of matrix a until they become minimal or disappear.
!
!If you have suspicions about convergence,
!you can jot down values in the a matrix
!after several runs. Use Job Manager.
!This matrix is the transformation matrix,
!or rotation matrix. If you encounter
!absolute matrix a values from one run to the next
!which are the same, using different start values,
!you're home free.  Depending upon start
!values, these elements will switch into
!different positions, and their signs will vary.
!Simplicity criterion will always be the same
!after valid runs. Valid rotations become apparent
!after a bit of experimentation with start values.
!
!Script by Peter Hoon, former Professor of
!Biostat and Psychology, University of TN
!Ctr. for the Health Sciences,
!December 20, 2003.  I am indebted to John Horn
!and USC fellowship support.
!Mike Neal provided valuable assistance in
!script design.
!
!phoon@attglobal.net
!
!
#ngroups 4
#define nv 10				!Number of variables
#define nf 4					!Number of factors

#define $varlist Run100 LngJmp ShtPut HiJmp Run400 Hurdle Discus PoleVlt Javelin Run1500   !Must have nv variable labels in this list
																						  !Olympic decathlon example

!#define $varlist Gaelic English Hist Arith Algebra Geom                                                                  !Lawley example

!#define $varlist Sent Vocab Sentcom Firslet Fourlet Sufices Letser Pedgree Letgrp                      !Thurstone (1947) example 

!#define $varlist Open Close                                                                                                              !US Lng Bond Fut Cnt meas model example 

#define $write N           		!Whether or not (Y or N)
							!you wish to write out loadings.

#define $outfile c:\varimax.out    !enter your path and filename
							    !for rotated mtx output

Group 1: First, perform Kaiser Normalization

	calculation				!calculation; no estimation

	begin matrices;
		L full nv nf			!input: unrotated fac pattern mtx L
		a full nf nf free		!transformation mtx a with eles free 
		q unity 1 nv			!unity row vector summates across rows
		m unity 1 nf			!unity col vector m' summates across cols
		p full 1 1			!mtx p is full with one element
		r full 1 1				!mtx r is full with one element
		u full 1 1			!mtx u is full with one element
		t full 1 1				!mtx t is full with one element
	end matrices;

							!Note that you will need to change the
							!test factor loading matrix input
							!to one of your choice, below.
							!Examples of both loading mtx read in
							!directly in MX set up script (for small matracies),
							!or disk read in are shown below.

	!matrix L				!Lawley and Maxwell (1971)
	!.553 .429				!verbal and quatitative
 	!.568 .288				!2 factors 6 variables
 	!.392 .450				!obtained by ML
 	!.740 -.273				!Row labels in grp 1
 	!.724 -.211				
 	!.595 -.132

	!matrix L				!Thurstone (1947)
	!.867 -.269 .021			!cited by McDonald, p. 58-60:
	!.881 -.237 -.057			!verbal ability, 
	!.826 -.222 -.031			!word fluency,
	!.657 .445 -.320			!verbal reasoning.
	!.630 .429 -.219			!3 factors 9 variables.
	!.597 .237 -.290			!Row labels in grp 1
	!.603 .320 .502
	!.646 .053 .291
	!.540 .381 .301

	matrix L
	-.090 .341 .830 -.169		!Linden (1977) Olympic Decathlon.
	.065 .433 .595 .275		!Can you find running endurance,
	-.139 .990 .000 .000		!arm strength, running speed,
	.156 .406 .336 .445		!explosive leg strength?
	.376 .245 .671 -.137		!Hulky 100 M folks
	-.021 .361 .425 .388		!and skinny Ethiopians
	-.063 .728 .030 .019		!are all here.
	.155 .264 .229 .394		!Obtained by ML
	-.026 .441 -.010 .098		!Row labels in grp 1.
	.998 .059 .000 .000

	!matrix L				!US Dec 2001 Lng Bond futures ZB Z1
	!.0953 .8824				!% chg Measmt model: open hi lo close.
	!.6170 .5852				!Two fac sol: "close" ,"open".
	!.6037 .5912				!Orthosim rot from EQS; 3655 bars, 35 tiks/bar.
	!.8847 .0848				!About a 5 Min. day trading bar.
							!Varimax virtually identical to Quartimax.

	!matrix L file=c:\Big FA\factor24.txt		!Disk read in of unrot fac pattern: 153 by 24.
	!matrix L file=c:\us\usunroteqs.txt		!Alternative unrot fac pattern read.
										!These are examples; set up your own.

	matrix t 4				!t raises each v ele to 4th pwr
	matrix u 2				!u raises each v ele to 2nd pwr
	matrix p nf				!p equal to number of factors
	matrix r nv				!r equal to number of variables

	begin algebra;

		b=\sqrt(\v2d((L^u)*m'));		!Compute b so we can
									!denormalize after varimax rotation
									!later in group 3.

		w=b~*L;						!Normalized unrot pattern mtx w.
									!Used b~ to normalize.
									!Later, to denormalize will use b.
	end algebra;

	option NO_output		!Can suppress uneeded output.

end group

Group 2: Find v that maximizes Kaiser Varimax simplicity criterion

	data ninputs=1

	matrices =group 1;		!access matrices from grp 1

	begin algebra;

		v=w*a;				!During successive estimations of a, we
							!recompute latest rotated pattern mtx v.
							!We roar through hundreds in .6 sec. 
	end algebra;

	covariance -((r^u)~*((r*(q*(v^t))) - ((q*(v^u))^u)))*m';

							!Kaiser (1958) Varimax simp criterion
							!as cited by McDonald (1985) p. 86. 							
							!Neg sign means we maximize.
							!m' makes unity col vector.

	!start .5 a 1 1			!Different but valid rot matrix
	!start .2 a 2 2			!from different start values.
							!Usually one required.
							!You can fool around.
	start -.2 a 2 1
	!start .4 a 1 2

	option NO_output		!Can suppress uneeded output.

	output user iterations=300 	!User funct is simplicity criterion.
								!Hold this tiger down to 300,
								!but you can change to more.
								!If huge unrot loading mtx input,
								!(i.e., 153 X 25), lower number
								!or be prepared to wait a while (30 mins?).
								!We're not dealing in compiled object code here.
								!Output ends grp 2; no end group needed.

Group 3: "De-normalize" Varimax rotated factor pattern matrix v

	calculation				!Calculation; no estimation.

	begin matrices;
		b computed = b 1		!access to b from group 1
		v computed = v 2		!access to v from group 2
                l full nv nf = l 1
        end matrices;

	begin algebra;
		z=b*v;				!De-normalize Vmax rot fac pat,
							!original fac pat h^2 are restored.
	end algebra;

	!labels row l $varlist
	!labels row z $varlist

#if $write = Y				!Write final Vmax rot pat z to disk.
							!Choose your own file & path up in Gp 1.
	option mxz=$outfile

#endif
            
end group

Group 4: Constraint group for elements of Varimax rotation mtx a

	data constraint ninputs=1

	matrices
		a full nf nf = a(2) 		!Test latest a eles from grp 2.
							!Be careful about syntax & spaces here:
							!a full nf nf = a(2) 
 
		i id nf nf				!Define i as identity mtx.
	constraint (a*a')-i;		!Keeps a eles bet 0 to 1 or -1 to 0.
							!Keeps axes orthogonal.

	option NO_output		!Can suppress uneeded output,
       !option th=-2

end group
