Advertisement
Guest User

D matrix struct

a guest
Oct 7th, 2013
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 12.14 KB | None | 0 0
  1. module matrix;
  2.  
  3. import std.math;
  4. import std.range;
  5. import std.format;
  6. import std.conv;
  7. import dlib.math.vector;
  8.  
  9. /*
  10.  * Square (NxN) matrix
  11.  */
  12. struct Matrix(T, size_t N)
  13. {
  14.    /*
  15.     * Return zero matrix
  16.     */
  17.     static opCall()
  18.     body
  19.     {
  20.         Matrix!(T,N) res;
  21.         foreach (ref v; res.arrayof)
  22.             v = 0;
  23.         return res;
  24.     }
  25.  
  26.    /*
  27.     * Create from array
  28.     */
  29.     this(F)(F[] arr)
  30.     in
  31.     {
  32.         assert (arr.length == N * N,
  33.             "Matrix!(T,N): wrong array length in constructor");
  34.     }
  35.     body
  36.     {
  37.         foreach (i, ref v; arrayof)
  38.             v = arr[i];
  39.     }
  40.  
  41.    /*
  42.     * Matrix * Matrix
  43.     */
  44.     Matrix!(T,N) opMul (Matrix!(T,N) mat)
  45.     body
  46.     {      
  47.         auto res = Matrix!(T,N)();
  48.  
  49.         foreach (y; 0..N)
  50.         foreach (x; 0..N)
  51.         {
  52.             auto i = y * N + x;
  53.  
  54.             foreach (k; 0..N)
  55.             {
  56.                 auto i1 = y * N + k;
  57.                 auto i2 = k * N + x;
  58.                 res.arrayof[i] += arrayof[i1] * mat.arrayof[i2];
  59.             }
  60.         }
  61.  
  62.         return res;
  63.     }
  64.  
  65.    /*
  66.     * Matrix *= Matrix
  67.     */
  68.     Matrix!(T,N) opMulAssign (Matrix!(T,N) mat)
  69.     body
  70.     {
  71.         auto res = Matrix!(T,N)();
  72.  
  73.         foreach (y; 0..N)
  74.         foreach (x; 0..N)
  75.         {
  76.             auto i = y * N + x;
  77.  
  78.             foreach (k; 0..N)
  79.             {
  80.                 auto i1 = y * N + k;
  81.                 auto i2 = k * N + x;
  82.                 res.arrayof[i] += arrayof[i1] * mat.arrayof[i2];
  83.             }
  84.         }
  85.  
  86.         arrayof[] = res.arrayof[];
  87.  
  88.         return mat;
  89.     }
  90.  
  91.    /*
  92.     * T = Matrix[x, y]
  93.     */
  94.     T opIndex(in size_t x, in size_t y)
  95.     body
  96.     {
  97.         return arrayof[y * N + x];
  98.     }
  99.  
  100.    /*
  101.     * Matrix[x, y] = T
  102.     */
  103.     T opIndexAssign(in T t, in size_t x, in size_t y)
  104.     body
  105.     {
  106.         return (arrayof[y * N + x] = t);
  107.     }
  108.  
  109.    /*
  110.     * Determinant of an upper-left 3x3 portion
  111.     */
  112.     static if (N >= 3)
  113.     {
  114.         T determinant3x3()
  115.         body
  116.         {
  117.             return a11 * (a33 * a22 - a32 * a23)
  118.                  - a21 * (a33 * a12 - a32 * a13)
  119.                  + a31 * (a23 * a12 - a22 * a13);
  120.         }
  121.     }
  122.  
  123.    /*
  124.     * Determinant
  125.     */
  126.     static if (N == 1)
  127.     {
  128.         T determinant()
  129.         body
  130.         {
  131.             return a11;
  132.         }
  133.     }
  134.     else
  135.     static if (N == 2)
  136.     {
  137.         T determinant()
  138.         body
  139.         {
  140.             return a11 * a22 - a12 * a21;
  141.         }
  142.     }    
  143.     else
  144.     static if (N == 3)
  145.     {
  146.         alias determinant3x3 determinant;
  147.     }
  148.     else
  149.     {
  150.        /*
  151.         * Determinant of a given upper-left portion
  152.         */
  153.         T determinant(size_t n = N)
  154.         body
  155.         {
  156.             T d = 0;
  157.  
  158.             if (n == 1)
  159.                 d = this[0,0];
  160.             else if (n == 2)
  161.                 d = this[0,0] * this[1,1] - this[1,0] * this[0,1];
  162.             else
  163.             {
  164.                 auto submat = Matrix!(T,N)();
  165.  
  166.                 for (uint c = 0; c < n; c++)
  167.                 {
  168.                     uint subi = 0;
  169.                     for (uint i = 1; i < n; i++)
  170.                     {
  171.                         uint subj = 0;
  172.                         for (uint j = 0; j < n; j++)
  173.                         {
  174.                             if (j == c)
  175.                                 continue;
  176.                             submat[subi, subj] = this[i, j];
  177.                             subj++;
  178.                         }
  179.                         subi++;
  180.                     }
  181.  
  182.                     d += pow(-1, c + 2.0) * this[0, c] * submat.determinant(n-1);
  183.                 }
  184.             }
  185.  
  186.             return d;
  187.         }
  188.     }
  189.  
  190.     alias determinant det;
  191.  
  192.    /*
  193.     * Return true if matrix is singular
  194.     */
  195.     bool singular() @property
  196.     body
  197.     {
  198.         return (determinant == 0);
  199.     }
  200.  
  201.    /*
  202.     * Transpose
  203.     */
  204.     void transpose()
  205.     body
  206.     {
  207.         Matrix!(T,N) res = transposed;
  208.         arrayof[] = res.arrayof[];
  209.     }
  210.  
  211.    /*
  212.     * Return the transposed matrix
  213.     */
  214.     Matrix!(T,N) transposed() @property
  215.     body
  216.     {
  217.         Matrix!(T,N) res;
  218.  
  219.         foreach(y; 0..N)
  220.         foreach(x; 0..N)
  221.             res.arrayof[y * N + x] = arrayof[x * N + y];
  222.  
  223.         return res;
  224.     }
  225.  
  226.    /*
  227.     * Inverse of a matrix
  228.     */
  229.     static if (N == 1)
  230.     {
  231.         Matrix!(T,N) inverse() @property
  232.         body
  233.         {
  234.             Matrix!(T,N) res;
  235.             res.a11 = 1.0 / a11;
  236.             return res;
  237.         }
  238.     }
  239.     else
  240.     static if (N == 2)
  241.     {
  242.         Matrix!(T,N) inverse() @property
  243.         body
  244.         {
  245.             Matrix!(T,N) res;
  246.  
  247.             T invd = 1.0 / (a11 * a22 - a12 * a21);
  248.            
  249.             res.a11 =  a22 * invd;
  250.             res.a12 = -a12 * invd;
  251.             res.a22 =  a11 * invd;
  252.             res.a21 = -a21 * invd;
  253.  
  254.             return res;
  255.         }
  256.     }
  257.     else
  258.     static if (N == 3)
  259.     {
  260.         Matrix!(T,N) inverse() @property
  261.         body
  262.         {
  263.             T d = determinant;
  264.        
  265.             T oneOverDet = 1.0 / d;
  266.        
  267.             Matrix!(T,N) res;
  268.        
  269.             res.a11 =  (a33 * a22 - a32 * a23) * oneOverDet;
  270.             res.a12 = -(a33 * a12 - a32 * a13) * oneOverDet;
  271.             res.a13 =  (a23 * a12 - a22 * a13) * oneOverDet;
  272.        
  273.             res.a21 = -(a33 * a21 - a31 * a23) * oneOverDet;
  274.             res.a22 =  (a33 * a11 - a31 * a13) * oneOverDet;
  275.             res.a23 = -(a23 * a11 - a21 * a13) * oneOverDet;
  276.        
  277.             res.a31 =  (a32 * a21 - a31 * a22) * oneOverDet;
  278.             res.a32 = -(a32 * a11 - a31 * a12) * oneOverDet;
  279.             res.a33 =  (a22 * a11 - a21 * a12) * oneOverDet;
  280.        
  281.             return res;
  282.         }
  283.     }
  284.     else
  285.     static if (N > 1)
  286.     {
  287.         static if (N == 4)
  288.         {
  289.            /*
  290.             * Inverse of a 4x4 affine matrix is a special case
  291.             */
  292.             private Matrix!(T,N) inverseAffine() @property
  293.             body
  294.             {
  295.                 T d = determinant3x3;
  296.                 //assert (fabs(det) > 0.000001);
  297.  
  298.                 T oneOverDet = 1.0 / d;
  299.  
  300.                 auto res = Matrix!(T,N)();
  301.  
  302.                 res.a11 = ((a22 * a33) - (a23 * a32)) * oneOverDet;
  303.                 res.a12 = ((a13 * a32) - (a12 * a33)) * oneOverDet;
  304.                 res.a13 = ((a12 * a23) - (a13 * a22)) * oneOverDet;
  305.  
  306.                 res.a21 = ((a23 * a31) - (a21 * a33)) * oneOverDet;
  307.                 res.a22 = ((a11 * a33) - (a13 * a31)) * oneOverDet;
  308.                 res.a23 = ((a13 * a21) - (a11 * a23)) * oneOverDet;
  309.  
  310.                 res.a31 = ((a21 * a32) - (a22 * a31)) * oneOverDet;
  311.                 res.a32 = ((a12 * a31) - (a11 * a32)) * oneOverDet;
  312.                 res.a33 = ((a11 * a22) - (a12 * a21)) * oneOverDet;
  313.      
  314.                 res.a41 = -((a41 * res.a11) + (a42 * res.a21) + (a43 * res.a31));
  315.                 res.a42 = -((a41 * res.a12) + (a42 * res.a22) + (a43 * res.a32));
  316.                 res.a43 = -((a41 * res.a13) + (a42 * res.a23) + (a43 * res.a33));
  317.  
  318.                 res.a44 = 1;
  319.  
  320.                 return res;
  321.             }
  322.  
  323.            /*
  324.             * Check if matrix represents affine transformation
  325.             */
  326.             bool affine() @property
  327.             {
  328.                 return (a14 == 0.0  
  329.                      && a24 == 0.0
  330.                      && a34 == 0.0
  331.                      && a44 == 1.0);
  332.             }
  333.         }
  334.  
  335.         Matrix!(T,N) inverse() @property
  336.         body
  337.         {
  338.             // Analytical inversion
  339.             enum inv = q{{
  340.                 auto res = adjugate;
  341.                 T oneOverDet = 1.0 / determinant;
  342.                 foreach(ref v; res.arrayof)
  343.                     v *= oneOverDet;
  344.                 return res;
  345.             }};
  346.  
  347.             static if (N == 4)
  348.             {
  349.                 if (affine)
  350.                     return inverseAffine;
  351.                 else
  352.                     mixin(inv);
  353.             }
  354.             else
  355.                 mixin(inv);
  356.         }
  357.     }
  358.  
  359.    /*
  360.     * Adjugate and cofactor matrices
  361.     */
  362.     static if (N == 1)
  363.     {
  364.         Matrix!(T,N) adjugate() @property
  365.         body
  366.         {
  367.             Matrix!(T,N) res;
  368.             res.arrayof[0] = 1;
  369.             return res;
  370.         }
  371.  
  372.         Matrix!(T,N) cofactor() @property
  373.         {
  374.             Matrix!(T,N) res;
  375.             res.arrayof[0] = 1;
  376.             return res;
  377.         }
  378.     }
  379.     else
  380.     static if (N == 2)
  381.     {
  382.         Matrix!(T,N) adjugate() @property
  383.         body
  384.         {
  385.             Matrix!(T,N) res;
  386.             res.arrayof[0] =  arrayof[3];
  387.             res.arrayof[1] = -arrayof[1];
  388.             res.arrayof[2] = -arrayof[2];
  389.             res.arrayof[3] =  arrayof[0];
  390.             return res;
  391.         }
  392.  
  393.         Matrix!(T,N) cofactor() @property
  394.         {
  395.             Matrix!(T,N) res;
  396.             res.arrayof[0] =  arrayof[3];
  397.             res.arrayof[1] = -arrayof[2];
  398.             res.arrayof[2] = -arrayof[1];
  399.             res.arrayof[3] =  arrayof[0];
  400.             return res;
  401.         }
  402.     }
  403.     else
  404.     static if (N > 1)
  405.     {
  406.         Matrix!(T,N) adjugate() @property
  407.         {
  408.             return cofactor.transposed;
  409.         }
  410.  
  411.         Matrix!(T,N) cofactor() @property
  412.         {
  413.             Matrix!(T,N) res;
  414.  
  415.             foreach(y; 0..N)
  416.             foreach(x; 0..N)
  417.             {
  418.                 auto submat = Matrix!(T,N-1)();
  419.  
  420.                 uint suby = 0;
  421.                 foreach(yy; 0..N)
  422.                 if (yy != y)
  423.                 {
  424.                     uint subx = 0;
  425.                     foreach(xx; 0..N)
  426.                     if (xx != x)
  427.                     {
  428.                         submat[subx, suby] = this[xx, yy];
  429.                         subx++;
  430.                     }
  431.                     suby++;
  432.                 }
  433.  
  434.                 res[x, y] = submat.determinant * (((x + y) % 2)? -1:1);
  435.             }
  436.  
  437.             return res;
  438.         }
  439.     }
  440.  
  441.    /*
  442.     * Convert to string
  443.     */
  444.     string toString() @property
  445.     body
  446.     {
  447.         auto writer = appender!string();
  448.         foreach (y; 0..N)
  449.         {
  450.             formattedWrite(writer, "[");
  451.             foreach (x; 0..N)
  452.             {
  453.                 formattedWrite(writer, "%s", arrayof[y * N + x]);
  454.                 if (x < N-1)
  455.                     formattedWrite(writer, ", ");
  456.             }
  457.             formattedWrite(writer, "]");
  458.             if (y < N-1)
  459.                 formattedWrite(writer, "\n");
  460.         }
  461.         return writer.data;
  462.     }
  463.  
  464.    /*
  465.     * Symbolic element access
  466.     */
  467.     private static string elements(string letter) @property
  468.     body
  469.     {
  470.         string res;
  471.         foreach (y; 0..N)
  472.         {
  473.             foreach (x; 0..N)
  474.             {
  475.                 res ~= "T " ~ letter ~ to!string(y+1) ~ to!string(x+1) ~ ";";
  476.             }
  477.         }
  478.         return res;
  479.     }
  480.  
  481.    /*
  482.     * Symbolic row vector access
  483.     */
  484.     private static string rowVectors() @property
  485.     body
  486.     {
  487.         string res;
  488.         foreach (y; 0..N)
  489.         {
  490.             res ~= "Vector!(T,N) row" ~ to!string(y+1) ~ ";";
  491.         }
  492.         return res;
  493.     }
  494.  
  495.    /*
  496.     * Matrix components
  497.     */
  498.     union
  499.     {
  500.         struct { mixin(elements("a")); }
  501.         struct { mixin(rowVectors); }
  502.  
  503.         T[N * N] arrayof;
  504.     }
  505. }
  506.  
  507. /*
  508.  * Predefined matrix type aliases
  509.  */
  510. alias Matrix!(float, 2) Matrix2x2f, Matrix2f;
  511. alias Matrix!(float, 3) Matrix3x3f, Matrix3f;
  512. alias Matrix!(float, 4) Matrix4x4f, Matrix4f;
  513. alias Matrix!(double, 2) Matrix2x2d, Matrix2d;
  514. alias Matrix!(double, 3) Matrix3x3d, Matrix3d;
  515. alias Matrix!(double, 4) Matrix4x4d, Matrix4d;
  516.  
  517. /*
  518.  * Matrix factory function
  519.  */
  520. auto matrixf(A...)(A arr)
  521. {
  522.     static assert(isPerfectSquare(arr.length),
  523.         "matrixf(A): input array length is not perfect square integer");
  524.     return Matrix!(float, cast(size_t)sqrt(cast(float)arr.length))([arr]);
  525. }
  526.  
  527. // TODO: move this to dlib.math.utils
  528. bool isPerfectSquare(float n)
  529. {
  530.     float r = sqrt(n);
  531.     return(r * r == n);
  532. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement