row_echelon_form_anynum.t 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!perl -T
  2. use 5.006;
  3. use strict;
  4. use warnings;
  5. use Test::More;
  6. BEGIN {
  7. eval { require Math::AnyNum };
  8. plan skip_all => "Math::AnyNum is not installed"
  9. if $@;
  10. plan skip_all => "Math::AnyNum >= 0.38 is needed"
  11. if $Math::AnyNum::VERSION < 0.38;
  12. }
  13. plan tests => 5;
  14. use Math::MatrixLUP;
  15. use Math::AnyNum qw(:overload);
  16. #<<<
  17. my $A = Math::MatrixLUP->new([ # base test case
  18. [ 1, 2, -1, -4 ],
  19. [ 2, 3, -1, -11 ],
  20. [ -2, 0, -3, 22 ],
  21. ]);
  22. is_deeply([@{$A->rref}], [
  23. [1, 0, 0, -8],
  24. [0, 1, 0, 1],
  25. [0, 0, 1, -2],
  26. ]);
  27. my $B = Math::MatrixLUP->new([ # mix of number styles
  28. [ 3, 0, -3, 1],
  29. [1/2, 3/2, -3, -2],
  30. [1/5, 4/5, -8/5, 3/10]
  31. ]);
  32. is_deeply([@{$B->rref}], [
  33. [1, 0, 0, -41/2],
  34. [0, 1, 0, -217/6],
  35. [0, 0, 1, -125/6],
  36. ]);
  37. my $C = Math::MatrixLUP->new([ # degenerate case
  38. [ 1, 2, 3, 4, 3, 1],
  39. [ 2, 4, 6, 2, 6, 2],
  40. [ 3, 6, 18, 9, 9, -6],
  41. [ 4, 8, 12, 10, 12, 4],
  42. [ 5, 10, 24, 11, 15, -4],
  43. ]);
  44. is_deeply([@{$C->rref}], [
  45. [1, 2, 0, 0, 3, 4],
  46. [0, 0, 1, 0, 0, -1],
  47. [0, 0, 0, 1, 0, 0],
  48. [0, 0, 0, 0, 0, 0],
  49. [0, 0, 0, 0, 0, 0],
  50. ]);
  51. #>>>
  52. sub gauss_jordan_solve {
  53. my ($matrix, $column_vector) = @_;
  54. [map { $_->[-1] } $matrix->concat($column_vector)->rref->rows];
  55. }
  56. {
  57. #<<<
  58. my $A = Math::MatrixLUP->new([
  59. [1, 0, 0, 0, 0, 0],
  60. [1, 63/100, 39/100, 1/4, 4/25, 1/10],
  61. [1, 63/50, 79/50, 99/50, 249/100, 313/100],
  62. [1, 47/25, 71/20, 67/10, 631/50, 119/5],
  63. [1, 251/100, 158/25, 397/25, 399/10, 2507/25],
  64. [1, 157/50, 987/100, 3101/100, 9741/100, 15301/50]
  65. ]);
  66. my $vector = Math::MatrixLUP->column([-1/100, 61/100, 91/100, 99/100, 3/5, 1/50]);
  67. my $solution = gauss_jordan_solve($A, $vector);
  68. is_deeply($solution, [
  69. -1/100,
  70. 655870882787/409205648497,
  71. -660131804286/409205648497,
  72. 509663229635/409205648497,
  73. -200915766608/409205648497,
  74. 26909648324/409205648497,
  75. ]);
  76. #>>>
  77. }
  78. sub gauss_jordan_invert {
  79. my ($matrix) = @_;
  80. my $n = scalar(@$matrix);
  81. my $I = Math::MatrixLUP->identity($n);
  82. Math::MatrixLUP->new([map { [@{$_}[$n .. $#{$_}]] } $matrix->concat($I)->rref->rows]);
  83. }
  84. {
  85. #<<<
  86. my $A = Math::MatrixLUP->new([
  87. [-1, -2, 3, 2],
  88. [-4, -1, 6, 2],
  89. [ 7, -8, 9, 1],
  90. [ 1, -2, 1, 3],
  91. ]);
  92. is_deeply($A->invert->as_array, gauss_jordan_invert($A)->as_array);
  93. #>>>
  94. }