Advertisement
runewalsh

Sparse Matrix (lab) 深刻なビジネス です

Dec 12th, 2011
435
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 11.06 KB | None | 0 0
  1. {$r-,q-}
  2. // Das Feen Reich!
  3. // Fus Roh Dah!~
  4.  
  5. unit SparseMatrix;
  6.  
  7. interface
  8.  
  9. uses
  10.   Math, SysUtils;
  11.  
  12. type
  13.   sint32 = longint;
  14.   uint32 = longword;
  15.   sint = sint32;
  16.   uint = uint32;       pUint = ^uint;
  17.   float = extended;
  18.   PtrUint = uint32; // unsigned integer with same size as pointer
  19.  
  20. const
  21.   FloatEps = 1e-17;
  22.  
  23. type
  24.   tSMHashValue = type uint32;
  25.  
  26.   pSMHashRec = ^tSMHashRec;
  27.   tSMHashRec = object
  28.     h: tSMHashValue;
  29.     x, y: uint;
  30.     value: float;
  31.     next: pSMHashRec;
  32.     procedure UpdateHash;
  33.   end;
  34.  
  35.   tSparseMatrixElemProc = procedure(var x, y: uint; var value: float; param: pointer);
  36.  
  37.   CSparseMatrix = class
  38.   private
  39.     _nh: uint;
  40.     _h: array of pSMHashRec;
  41.     _sizeX, _sizeY: uint;
  42.     _relocating: boolean;
  43.     procedure _AddHashRec(r: pSMHashRec);
  44.     function _FindHashRec(x, y: uint): pSMHashRec;
  45.     procedure _RemHashRec(x, y: uint);
  46.     procedure _RelocateHash(force: boolean = false);
  47.     function _GetCell(x, y: uint): float;
  48.     procedure _SetCell(x, y: uint; const value: float);
  49.     procedure _SetSizeX(newSizeX: uint);
  50.     procedure _SetSizeY(newSizeY: uint);
  51.   public
  52.     constructor Create(newSizeX, newSizeY: uint); overload;
  53.     constructor Create(m: CSparseMatrix); overload;
  54.     destructor Destroy; override;
  55.     procedure ForEach(proc: tSparseMatrixElemProc; param: pointer);
  56.     procedure RemoveCol(x: uint);
  57.     procedure RemoveRow(y: uint);
  58.     procedure SwapRows(y1, y2: uint);
  59.     procedure AddRow(target, row: uint; factor: float);
  60.     function GetMinor(x, y: uint): float;
  61.     function GetAlgebraicComplement(x, y: uint): float;
  62.     function Det: float;
  63.     procedure DoForwardGauss;
  64.  
  65.     property SizeX: uint read _sizeX write _SetSizeX;
  66.     property SizeY: uint read _sizeY write _SetSizeY;
  67.     property Cells[x, y: uint]: float read _GetCell write _SetCell; default;
  68.   end;
  69.  
  70.   function SparseMul(a, b: CSparseMatrix): CSparseMatrix;
  71.  
  72.  
  73. implementation
  74.  
  75.  
  76.   {function HashUint32(x: uint32): tSMHashValue;
  77.   begin
  78.     x := (x + $7ed55d16) + (x shl 12);
  79.     x := (x xor $c761c23c) xor (x shr 19);
  80.     x := (x + $165667b1) + (x shl 5);
  81.     x := (x + $d3a2646c) xor (x shl 9);
  82.     x := (x + $fd7046c5) + (x shl 3);
  83.     x := (x xor $b55a4f09) xor (x shr 16);
  84.     result := x;
  85.   end;}
  86.  
  87.   function HashUint32(x: uint32): tSMHashValue;
  88.   begin
  89.     x := x + not (x shl 15);
  90.     x := x xor (x shr 10);
  91.     x := x + (x shl 3);
  92.     x := x xor (x shr 6);
  93.     x := x + not (x shl 11);
  94.     x := x xor (x shr 16);
  95.     result := x;
  96.   end;
  97.  
  98.   function HashUint32XY(x, y: uint32): tSMHashValue;
  99.   begin
  100.     result := HashUint32(x) xor HashUint32(y);
  101.   end;
  102.  
  103.   function IsZero(x: float): boolean;
  104.   begin
  105.     result := abs(x) < FloatEps;
  106.   end;
  107.  
  108.   function NotZero(x: float): boolean;
  109.   begin
  110.     result := abs(x) >= FloatEps;
  111.   end;
  112.  
  113.   function IsNaN(x: float): boolean;
  114.   begin
  115.     result := x <> x;
  116.   end;
  117.  
  118.   function IsInf(x: float): boolean;
  119.   begin
  120.     result := x > x;
  121.   end;
  122.  
  123.   function IsNegInf(x: float): boolean;
  124.   begin
  125.     result := x < x;
  126.   end;
  127.  
  128.  
  129.   procedure tSMHashRec.UpdateHash;
  130.   begin
  131.     h := HashUint32XY(x, y);
  132.   end;
  133.  
  134.   procedure CSparseMatrix._AddHashRec(r: pSMHashRec);
  135.   var
  136.     i: uint;
  137.   begin
  138.     if not Assigned(r) then exit;
  139.     _RemHashRec(r^.x, r^.y);
  140.     i := r^.h mod uint(length(_h));
  141.     r^.next := _h[i];
  142.     _h[i] := r;
  143.     inc(_nh);
  144.     _RelocateHash;
  145.   end;
  146.  
  147.   function CSparseMatrix._FindHashRec(x, y: uint): pSMHashRec;
  148.   var
  149.     i: uint;
  150.   begin
  151.     i := HashUint32XY(x, y) mod uint(length(_h));
  152.     result := _h[i];
  153.     while (Assigned(result)) and ((result^.x <> x) or (result^.y <> y)) do
  154.       result := result^.next;
  155.   end;
  156.  
  157.   procedure CSparseMatrix._RemHashRec(x, y: uint);
  158.   var
  159.     r, cur, prev: pSMHashRec;
  160.     i: uint;
  161.   begin
  162.     r := _FindHashRec(x, y);
  163.     if not Assigned(r) then exit;
  164.     i := r^.h mod uint(length(_h));
  165.     prev := nil;
  166.     cur := _h[i];
  167.     while Assigned(cur) do
  168.     begin
  169.       if cur = r then
  170.       begin
  171.         if Assigned(prev) then
  172.           prev^.next := cur^.next
  173.         else
  174.           _h[i] := cur^.next;
  175.         break;
  176.       end;
  177.       prev := cur;
  178.       cur := cur^.next;
  179.     end;
  180.     dispose(r);
  181.     dec(_nh);
  182.     _RelocateHash;
  183.   end;
  184.  
  185.   procedure CSparseMatrix._RelocateHash(force: boolean = false);
  186.   var
  187.     store, c, t: pSMHashRec;
  188.     i: uint;
  189.   begin
  190.     if (_nh >= uint(length(_h) div 2)) and (_nh <= uint(2*length(_h))) and
  191.       (not force) then
  192.       exit;
  193.     if _relocating then exit;
  194.     _relocating := true;
  195.     store := nil;
  196.     for i := 0 to High(_h) do
  197.     begin
  198.       c := _h[i];
  199.       while Assigned(c) do
  200.       begin
  201.         t := c^.next;
  202.         c^.next := store;
  203.         store := c;
  204.         c := t;
  205.       end;
  206.     end;
  207.     if _nh > 0 then SetLength(_h, _nh) else SetLength(_h, 1);
  208.     for i := 0 to High(_h) do _h[i] := nil;
  209.     _nh := 0;
  210.     while Assigned(store) do
  211.     begin
  212.       t := store;
  213.       store := store^.next;
  214.       _AddHashRec(t);
  215.     end;
  216.     _relocating := false;
  217.   end;
  218.  
  219.   function CSparseMatrix._GetCell(x, y: uint): float;
  220.   var
  221.     c: pSMHashRec;
  222.   begin
  223.     if (x >= _sizeX) or (y >= _sizeY) then
  224.     begin
  225.       result := 0.0;
  226.       exit;
  227.     end;
  228.     c := _FindHashRec(x, y);
  229.     if Assigned(c) then
  230.       result := c^.value
  231.     else
  232.       result := 0.0;
  233.   end;
  234.  
  235.   procedure CSparseMatrix._SetCell(x, y: uint; const value: float);
  236.   var
  237.     c: pSMHashRec;
  238.   begin
  239.     if (x >= _sizeX) or (y >= _sizeY) then exit;
  240.     if IsZero(value) then
  241.       _RemHashRec(x, y)
  242.     else
  243.     begin
  244.       new(c);
  245.       c^.x := x;
  246.       c^.y := y;
  247.       c^.value := value;
  248.       c^.UpdateHash;
  249.       _AddHashRec(c);
  250.     end;
  251.   end;
  252.  
  253.   procedure __elemfits(var x, y: uint; var value: float; param: pointer);
  254.   var
  255.     m: CSparseMatrix absolute param;
  256.   begin
  257.     if (x >= m.SizeX) or (y >= m.SizeY) then value := 0.0;
  258.   end;
  259.  
  260.   procedure CSparseMatrix._SetSizeX(newSizeX: uint);
  261.   begin
  262.     if _sizeX <> newSizeX then
  263.     begin
  264.       _sizeX := newSizeX;
  265.       ForEach(__elemfits, self);
  266.     end;
  267.   end;
  268.  
  269.   procedure CSparseMatrix._SetSizeY(newSizeY: uint);
  270.   begin
  271.     if _sizeY <> newSizeY then
  272.     begin
  273.       _sizeY := newSizeY;
  274.       ForEach(__elemfits, self);
  275.     end;
  276.   end;
  277.  
  278.   constructor CSparseMatrix.Create(newSizeX, newSizeY: uint);
  279.   begin
  280.     inherited Create;
  281.     _relocating := false;
  282.     _nh := 0;
  283.     SetLength(_h, 1);
  284.     _h[0] := nil;
  285.     _sizeX := 0;
  286.     _sizeY := 0;
  287.     SizeX := newSizeX;
  288.     SizeY := newSizeY;
  289.   end;
  290.  
  291.   procedure __AddElem(var x, y: uint; var value: float; param: pointer);
  292.   begin
  293.     CSparseMatrix(param)[x, y] := value;
  294.   end;
  295.  
  296.   constructor CSparseMatrix.Create(m: CSparseMatrix);
  297.   begin
  298.     Create(m.SizeX, m.SizeY);
  299.     m.ForEach(__AddElem, self);
  300.   end;
  301.  
  302.   destructor CSparseMatrix.Destroy;
  303.   var
  304.     c, t: pSMHashRec;
  305.     i: sint;
  306.   begin
  307.     for i := 0 to High(_h) do
  308.     begin
  309.       c := _h[i];
  310.       while Assigned(c) do
  311.       begin
  312.         t := c;
  313.         c := c^.next;
  314.         dispose(t);
  315.       end;
  316.     end;
  317.     inherited Destroy;
  318.   end;
  319.  
  320.   procedure CSparseMatrix.ForEach(proc: tSparseMatrixElemProc; param: pointer);
  321.   var
  322.     i: sint;
  323.     prev, c, t: pSMHashRec;
  324.   begin
  325.     for i := 0 to High(_h) do
  326.     begin
  327.       prev := nil;
  328.       c := _h[i];
  329.       while Assigned(c) do
  330.       begin
  331.         t := c;
  332.         c := c^.next;
  333.         proc(t^.x, t^.y, t^.value, param);
  334.         if NotZero(t^.value) then
  335.         begin    
  336.           t^.UpdateHash;
  337.           prev := t;
  338.         end else
  339.         begin
  340.           if Assigned(prev) then
  341.             prev^.next := c
  342.           else
  343.             _h[i] := c;
  344.           dispose(t);
  345.           dec(_nh);
  346.         end;
  347.       end;
  348.     end;
  349.     _RelocateHash(true);
  350.   end;
  351.  
  352.   procedure __RemCol(var x, y: uint; var value: float; param: pointer);
  353.   begin
  354.     if x = PtrUint(param) then value := 0.0 else
  355.     if x > PtrUint(param) then dec(x);
  356.   end;
  357.  
  358.   procedure __RemRow(var x, y: uint; var value: float; param: pointer);
  359.   begin
  360.     if y = PtrUint(param) then value := 0.0 else
  361.     if y > PtrUint(param) then dec(y);
  362.   end;
  363.  
  364.   procedure CSparseMatrix.RemoveCol(x: uint);
  365.   begin
  366.     if x >= _sizeX then exit;
  367.     ForEach(__RemCol, pointer(PtrUint(x)));
  368.     SizeX := SizeX - 1;
  369.   end;
  370.  
  371.   procedure CSparseMatrix.RemoveRow(y: uint);
  372.   begin
  373.     if y >= _sizeX then exit;
  374.     ForEach(__RemRow, pointer(PtrUint(y)));
  375.     SizeY := SizeY - 1;
  376.   end;
  377.  
  378.   procedure CSparseMatrix.SwapRows(y1, y2: uint);
  379.   var
  380.     t: float;
  381.     i: sint;
  382.   begin
  383.     if (y1 >= _sizeY) or (y2 >= _sizeY) or (y1 = y2) then exit;
  384.     for i := 0 to _sizeX-1 do
  385.     begin
  386.       t := self[i, y1];
  387.       self[i, y1] := self[i, y2];
  388.       self[i, y2] := t;
  389.     end;
  390.   end;
  391.  
  392.   procedure CSparseMatrix.AddRow(target, row: uint; factor: float);
  393.   var
  394.     i: sint;
  395.   begin
  396.     if (target >= _sizeY) or (row >= _sizeY) then exit;
  397.     for i := 0 to _sizeX-1 do
  398.       self[i, target] := self[i, target] + self[i, row] * factor;
  399.   end;
  400.  
  401.   function CSparseMatrix.GetMinor(x, y: uint): float;
  402.   var
  403.     tm: CSparseMatrix;
  404.   begin
  405.     if (x >= _sizeX) or (y >= _sizeY) or (_sizeX <> _sizeY) or (_sizeX <= 1) then
  406.     begin
  407.       result := NaN;
  408.       exit;
  409.     end;
  410.     // terrible! :D
  411.     tm := CSparseMatrix.Create(self);
  412.     tm.RemoveCol(x);
  413.     tm.RemoveRow(y);
  414.     result := tm.Det;
  415.     tm.Free;
  416.   end;
  417.  
  418.   function CSparseMatrix.GetAlgebraicComplement(x, y: uint): float;
  419.   begin
  420.     result := GetMinor(x, y);
  421.     if (not IsNaN(result)) and odd(x + y) then result := -result;
  422.   end;
  423.  
  424.   function CSparseMatrix.Det: float;
  425.   var
  426.     i: sint;
  427.     v: float;
  428.   begin
  429.     if (_sizeX <> _sizeY) or (_sizeX = 0) then
  430.     begin
  431.       result := NaN;
  432.       exit;
  433.     end;
  434.     if _sizeX = 1 then
  435.     begin
  436.       result := self[0, 0];
  437.       exit;
  438.     end;
  439.     result := 0.0;
  440.     for i := 0 to _sizeX-1 do
  441.     begin
  442.       v := self[i, 0];
  443.       if NotZero(v) then
  444.         result := result + v * GetAlgebraicComplement(i, 0);
  445.     end;
  446.   end;
  447.  
  448.   procedure CSparseMatrix.DoForwardGauss;
  449.   var
  450.     i, j, sy, firstnonzero: sint;
  451.     x: float;
  452.   begin
  453.     sy := 0;
  454.     for i := 0 to _sizeX-1 do
  455.     begin
  456.       firstnonzero := -1;
  457.       for j := sy to _sizeY-1 do
  458.         if NotZero(self[i, j]) then
  459.         begin
  460.           firstnonzero := j;
  461.           break;
  462.         end;
  463.       if firstnonzero = -1 then continue;
  464.       SwapRows(sy, firstnonzero);
  465.       x := self[i, sy];
  466.       for j := sy+1 to _sizeY-1 do
  467.         AddRow(j, sy, -self[i, j] / x);
  468.       inc(sy);
  469.     end;
  470.   end;
  471.  
  472.   function SparseMul(a, b: CSparseMatrix): CSparseMatrix;
  473.   var
  474.     x, y, k: sint;
  475.     v: float;
  476.   begin
  477.     if a.SizeX <> b.SizeY then
  478.     begin
  479.       result := nil;
  480.       exit;
  481.     end;
  482.     result := CSparseMatrix.Create(b.SizeX, a.SizeY);
  483.     for x := 0 to result.SizeX-1 do
  484.       for y := 0 to result.SizeY-1 do
  485.       begin
  486.         v := 0.0;
  487.         for k := 0 to a.SizeX-1 do
  488.           v := v + a[k, y] * b[x, k];
  489.         result[x, y] := v;
  490.       end;
  491.   end;
  492.  
  493. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement