\(\(\( (*\ 
      10^6 - Fold\ \ Increase\ \ in\ \ Computation\ \ Speed\ \ of\ \ a\ \ Scroll\ \ Matrix\ \ Pseudoinverse\ *) \)\(
\)\( (*\ 
      Copyright\ \ \ Doug\ Youvan\ \ \ May\ 29, \ 
      2006\ \ \ \ www . youvan . com\ \ \ \ www . pseudocolor . 
          com\ *) \)\(
\)\(
\)\( (*\ 
      64\ codons\ in\ binary\ ' 
        scroll\ matrix'\ in\ canonical\ order\ as\ defined\ by\ the\ following\ *) \)\(
\)\(
\)\(t =. ; \ 
    g =. ; c =. ; a =. ;

    \(nucgc = Tuples[{a, c, g, t}, 3];\)

    \(a = {0, 0, 0, 1};\)

    \(c = {0, 0, 1, 0};\)

    \(g = {0, 1, 0, 0};\)

    \(t = {1, 0, 0, 0};\)

    \(nucgc = Flatten[nucgc];\)

    \(nucgc = Partition[nucgc, 12];\)
 (*\ 
      end\ of\ definition\ *) 
 (*\ 
      this\ could\ also\ be\ seen\ as\ a\ unique\ mapping\ of\ alphanumerics\ onto\ a\ series\ of\ the\ powers\ of\ base\ 2; \ 
      in\ this\ particular\ case\ of\ an\ alphabet\ of\ a, \ c, \ g, \ 
      t\ the\ mapping\ is\ onto\ 1, \ 2, \ 4, \ 
      8\ in\ base\ 2\ *) 

    ArrayPlot[nucgc]

    \)\)\)

date1 = 
        Date[];

    pin = PseudoInverse[nucgc];

    date2 = Date[];

    timeforpin = date2 - date1

    ArrayPlot[pin]

(* for a scroll matrix,  
      reproduce pseudoinverse by using only transpose and solving the following equations requiring only 30 ms of time *) 

trana =. ;

    tranb =. ;

    date3 = Date[];

    Solve[
      pin == ((Transpose[nucgc]*trana) -  tranb),  {trana, 
        tranb}]

    date4 = Date[];

    timeforsolve = date4 - date3

date5 = 
        Date[];

    ma = ((Transpose[nucgc]/16) - 1/96);

    date6 = Date[];

    timeforma = date6 - date5

  


    ArrayPlot[ma]


    ma==pin

(* Test scroll method' 
            s speed by converting the scroll matrix ' nucgc' to ' 
            nucgcns' by dropping three rows :  57,51,49, yielding a 61  x12 matrix; then comment out so it does not rerun; this takes about 2.2 hrs as it did in Example 17 *)

(*
nucgcns = 
          Drop[nucgc, {57}]; 
nucgcns = 
          Drop[nucgcns, {51}]; 
nucgcns = 
          Drop[nucgcns, {49}]; 

date8 = 
          Date[]; 
pinns = 
          PseudoInverse[nucgcns]; 
date9 = 
          Date[]; 
timeforpin = date9 - date8 

    *)

ArrayPlot[
        pinns]

(* 
      check how scroll method works on simpler scroll matrices *) 

simple1 = 
{{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 
            1}, 
{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 
            0}, 
{0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 
            0}, 
{0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 
            0}};


    pis1 = PseudoInverse[simple1]

simple2 = 
{{0, 1,   0, 
            1}, 
{0, 1,   1, 0}, 
{1, 
            0,   0, 1}, 
{1, 0,   0, 
            1}};

    
pis2 = PseudoInverse[simple2]

simple3 = 
{{0, 0, 1,  0,  0, 
            1}, 
{0, 0, 1,   0, 1, 
            0}, 
{0, 0, 1,   1, 0, 
            0}, 
{0, 1, 0,  0,  0, 
            1}, 
{0, 1, 0,   0, 1, 
            0}, 
{0, 1, 0,   1, 0, 
            0}, 
{1, 0, 0,  0,  0, 
            1}, 
{1, 0, 0,   0, 1, 
            0}, 
{1, 0, 0,   1, 0, 
            0}};

    
pis3 = PseudoInverse[simple3]

Total[Flatten[simple3]]

Flatten[pis3, 3]

Total[Flatten[pis3, 3]]

(* 
      test for invariance by randomizing rows of simple3 to make simple31 *) 

simple31 = 
{{0, 0, 1,  0,  0, 1}, 
{0, 1, 0,  
            0,  0, 1}, 
{1, 0, 0,   0, 1, 
            0}, 
{0, 1, 0,   0, 1, 
            0}, 
{0, 1, 0,   1, 0, 
            0}, 
{1, 0, 0,  0,  0, 
            1}, 
{0, 0, 1,   0, 1, 
            0}, 
{0, 0, 1,   1, 0, 
            0}, 
{1, 0, 0,   1, 0, 
            0}};


    pis31 = PseudoInverse[simple31]

simple3 == simple31
pis3 == pis31
Total[Flatten[simple3]] == 
      Total[Flatten[simple31]]
Total[Flatten[pis31, 3]] == 
      Total[Flatten[pis31, 3]]
Min[pis3] == Min[pis31]
Max[pis3] == Max[pis31]
Max[pis3] - Min[pis3] == Max[pis31] - Min[pis31]

MatrixForm[pis3]
ma = 0. 
ma = ((Transpose[simple3]*6) - 1)/
          18;
MatrixForm[ma]
ma == pis3