## Diagonalize a matrix

Solved
Super Contributor
Posts: 355

# Diagonalize a matrix

Hello!

I would appreciate help to "diagonalize" a dataset in the following way:

Data Coeff;
Input Product1-Product3;
Datalines;
5 0 0
5 0 2
0 0 8
0 1 0
;
Run;

The goal is:

Data Want_1; * rows form the "main diagonal";
Input X11-X13 X21-X23 X31-X33 X41-X43;
Datalines;
5 0 0 . . . . . . . . .
. . . 5 0 2 . . . . . .
. . . . . . 0 0 8 . . .
. . . . . . . . . 0 1 0
;
Run;

Data Want_2; * columns form the "main diagonal";
Input X11-X13 X21-X23 X31-X33 X41-X43;
Datalines;
5 . . 5 . . 0 . . 0 . .
. 0 . . 0 . . 0 . . 1 .
. . 0 . . 2 . . 8 . . 0
;
Run;

Please note that the variable names in the 2 Haves are important.

Thanks&kind regards

Accepted Solutions
Solution
‎12-03-2014 11:39 AM
Posts: 3,167

## Re: Diagonalize a matrix

WANT_2 will be the similar process after transposing:

Data Coeff;

Input Product1-Product3;

Datalines;

5 0 0

5 0 2

0 0 8

0 1 0

;

Run;

PROC TRANSPOSE DATA=COEFF OUT=H2;

VAR _ALL_;

RUN;

proc sql NOPRINT;

select nobs*nvar, NVAR into :nvar, :VNUM TRIMMED from dictionary.tables where LIBNAME='WORK' AND MEMNAME='COEFF';

QUIT;

DATA WANT_1;

ARRAY X(&NVAR.);

SET COEFF;

ARRAY PRO PROD:;

DO OVER PRO;

X((_N_-1)*&VNUM+_I_)=PRO;

END;

KEEP X:;

RUN;

DATA WANT_2;

ARRAY X(&NVAR.);

SET H2;

ARRAY COL COL:;

DO OVER COL;

X(_N_+(_I_-1)*&VNUM.)=COL;

END;

KEEP X:;

RUN;

QUIT;

Haikuo

All Replies
Super User
Posts: 9,599

## Re: Diagonalize a matrix

For want_1:

data want_1;

set coeff;

retain offset;

array vals{12} x11-x13 x21-x23 x31-x33 x41-x43;

array prod{3} product1-product3;

if _n_=1 then offset=0;

do i=1 to 3;

do j=1 to 3;

vals{sum(offset,j)}=prod{i};

end;

end;

offset=offset+3;

run;

For want_2, you can modify want_1 code, not particularly difficult.  Just change the loop for j to do 1,4,7,11;

Super Contributor
Posts: 355

## Re: Diagonalize a matrix

Thanks for your quick reply. But I'm afraid the result I'm getting is:

0 0 0 . . . . . . . . .

. . . 2 2 2 . . . . . .

. . . . . . 8 8 8 . . .

. . . . . . . . . 0 0 0

What would be great - but didn't directly ask for above - is a dynamic method to transform the data. I can't think of a method to do the array-declaration "array vals{12} x11-x13 x21-x23 x31-x33 x41-x43;" with a macro-variable.

Super User
Posts: 9,599

## Re: Diagonalize a matrix

Well, try this:

data _null_;
set sashelp.vtable (where=(libname="WORK" and memname="COEFF"));
length temp \$2000.;
do i=1 to nobs;
do j=1 to 3;
temp=catx(' ',temp,'X'||strip(put((i*10)+j,best.)));
end;
end;
call symputx('VLIST',temp);
call symputx('ARRAY_NUM',nobs*3);
run;

data inter (drop=temp i);
set coeff;
array product _all_;
array vals{&ARRAY_NUM.} &VLIST.;
length temp \$2000.;
temp=cats(of product{*});
temp=repeat(' ',(_n_-1) * 3)||strip(temp);
temp=substr(temp,2);
do i=1 to &ARRAY_NUM.;
vals{i}=input(substr(temp,i,1),best.);
end;
run;

It should be flexible, however you are limited to the 2000 characters.  I have to ask, why do you want this kind of structure?

Super Contributor
Posts: 355

## Re: Diagonalize a matrix

Sorry. I didn't get it the first time. I played around with your first code, and Want_1 should work now (but isn't dynamic yet):

Data Coeff;
Input Product1-Product3;
Datalines;
5 0 0
5 0 2
0 0 8
0 1 0
;
Run;

Data Want_1 (Keep=X;
Set Coeff;
Retain Offset 0;
Offset+1;
Array P {*} Product:;
Array X {12} X11-X13 X21-X23 X31-X33 X41-X43;
Do i=1 To 3;
X{Offset*3-3+i}=P{i};
End;
Run;

Super Contributor
Posts: 355

## Re: Diagonalize a matrix

Overlooked your question. A couple of weeks ago I think ksharp and pgstats posted the following code:

data lincon;
Input x11 x12 x21 x22 x31 x32 _RHS_ _TYPE_ \$;
datalines;
1 1 . . . . 5 EQ
. . 1 1 . . 5 EQ
. . . . 1 1 7 LE
. . . . 1 1 4 GE
1 . 1 . 1 . 8 EQ
. 1 . 1 . 1 9 EQ
;

proc CLP condata=lincon USECONDATAVARS=1  domain=[1,10] findall out=soln;
run;

proc print data=soln; run;

.. And the lincon-dataset has the structure of Want_1 & Want_2 combined ..

Solution
‎12-03-2014 11:39 AM
Posts: 3,167

## Re: Diagonalize a matrix

WANT_2 will be the similar process after transposing:

Data Coeff;

Input Product1-Product3;

Datalines;

5 0 0

5 0 2

0 0 8

0 1 0

;

Run;

PROC TRANSPOSE DATA=COEFF OUT=H2;

VAR _ALL_;

RUN;

proc sql NOPRINT;

select nobs*nvar, NVAR into :nvar, :VNUM TRIMMED from dictionary.tables where LIBNAME='WORK' AND MEMNAME='COEFF';

QUIT;

DATA WANT_1;

ARRAY X(&NVAR.);

SET COEFF;

ARRAY PRO PROD:;

DO OVER PRO;

X((_N_-1)*&VNUM+_I_)=PRO;

END;

KEEP X:;

RUN;

DATA WANT_2;

ARRAY X(&NVAR.);

SET H2;

ARRAY COL COL:;

DO OVER COL;

X(_N_+(_I_-1)*&VNUM.)=COL;

END;

KEEP X:;

RUN;

QUIT;

Haikuo

Super Contributor
Posts: 355

## Re: Diagonalize a matrix

Many thanks to both of you!

Want_1 & Want_2 work.

🔒 This topic is solved and locked.