Advertisement
runewalsh

Sparse Matrix (standard types) / 私を貫く赤い光

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