Diagonalize a matrix

Accepted Solution Solved
Reply
Super Contributor
Posts: 336
Accepted Solution

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
Respected Advisor
Posts: 3,124

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

View solution in original post


All Replies
Esteemed Advisor
Esteemed Advisor
Posts: 7,263

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: 336

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.

Esteemed Advisor
Esteemed Advisor
Posts: 7,263

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: 336

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=XSmiley Happy;
  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: 336

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
Respected Advisor
Posts: 3,124

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: 336

Re: Diagonalize a matrix

Many thanks to both of you!

Want_1 & Want_2 work.

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 7 replies
  • 264 views
  • 6 likes
  • 3 in conversation