fast_matrix 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0e98406e186191f8308eeca9cc81293343f44fd4a6e97559c6b4e3ce2d8b0b7
4
- data.tar.gz: a6e2c1b4f49e62c76e27e23df7a358ca22c927099868f990488e5ea5c1ca21e6
3
+ metadata.gz: 34d254515edd7b453efe7fdedb7b360c462faa53c9ec13de7f4beb5cf989e536
4
+ data.tar.gz: 5b9c35116c61a67f498badf12980d71d275e8020900ab48eb710aa74cd17ed71
5
5
  SHA512:
6
- metadata.gz: 596d0c7a7bec078b328968e0a1a0c20e83076215594807395e2323eabf239fa5a61d88cde3564219b28f8520f97d40e06d34e39e5aea8ec0db0c08befddc2b39
7
- data.tar.gz: a53d3c85372d7f9273cdee68789a2fadecae44f05f2f6244c6661970de890b246e81d44800354964ea32cf5f80292f2464ca7fb6b2b30683a90f6fcd3cdeba74
6
+ metadata.gz: a011340ce71b58856512df1b6da78af5f510ae6789a8cdfd69f3793370533f66d6c2a6647abde1c5ef42a2928f8118528d976f6402be3ff3a81f16e519ec700a
7
+ data.tar.gz: f618591f305fb3d9d2b97819833398e571fa99e0fcf43ad74fc8152e9fb3e6c7d97a1128933cbbc9b8b4b8bda642e1d6f5e7be4a04abc1c47d994981f43ac560
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
- [![Build Status](https://travis-ci.org/mmcs-ruby/fast_matrix.svg?branch=master)](https://travis-ci.org/mmcs-ruby/fast_matrix)
2
- [![Maintainability](https://api.codeclimate.com/v1/badges/fd171bae2ca444aaca29/maintainability)](https://codeclimate.com/github/mmcs-ruby/fast_matrix/maintainability)
3
- [![Test Coverage](https://api.codeclimate.com/v1/badges/fd171bae2ca444aaca29/test_coverage)](https://codeclimate.com/github/mmcs-ruby/fast_matrix/test_coverage)
1
+ |Gem|Activity|Code|Issue|Statistic|
2
+ |--:|--:|--:|--:|--:|
3
+ |![Gem](https://img.shields.io/gem/v/fast_matrix?color=light)|![GitHub last commit](https://img.shields.io/github/last-commit/mmcs-ruby/fast_matrix)|[![Build Status](https://travis-ci.org/mmcs-ruby/fast_matrix.svg?branch=master)](https://travis-ci.org/mmcs-ruby/fast_matrix)|![GitHub issues](https://img.shields.io/github/issues-raw/mmcs-ruby/fast_matrix)|[![Top language](https://img.shields.io/github/languages/top/mmcs-ruby/fast_matrix.svg)](https://img.shields.io/github/languages/top/mmcs-ruby/fast_matrix.svg)
4
+ |[![Downloads](https://img.shields.io/gem/dt/fast_matrix.svg)]((https://img.shields.io/gem/dt/fast_matrix.svg))|![GitHub commits since tagged version](https://img.shields.io/github/commits-since/mmcs-ruby/fast_matrix/v0.2.0/develop?color=light)|[![Maintainability](https://api.codeclimate.com/v1/badges/fd171bae2ca444aaca29/maintainability)](https://codeclimate.com/github/mmcs-ruby/fast_matrix/maintainability)|![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/mmcs-ruby/fast_matrix)|[![Languages](https://img.shields.io/github/languages/count/mmcs-ruby/fast_matrix.svg)](https://img.shields.io/github/languages/count/mmcs-ruby/fast_matrix.svg)
5
+ |[![Downloads Latest](https://img.shields.io/gem/dtv/fast_matrix.svg)](https://badge.fury.io/rb/fast_matrix.svg)|![GitHub commit activity](https://img.shields.io/github/commit-activity/m/mmcs-ruby/fast_matrix?color=light)|[![Test Coverage](https://api.codeclimate.com/v1/badges/fd171bae2ca444aaca29/test_coverage)](https://codeclimate.com/github/mmcs-ruby/fast_matrix/test_coverage)|![GitHub issues by-label](https://img.shields.io/github/issues-raw/mmcs-ruby/fast_matrix/bug)|![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/mmcs-ruby/fast_matrix)
4
6
 
5
7
  # FastMatrix
6
8
 
@@ -78,6 +78,30 @@ bool greater_or_equal_d_array(int len, const double* A, const double* B)
78
78
  return true;
79
79
  }
80
80
 
81
+ bool less_or_equal_d_array(int len, const double* A, const double* B)
82
+ {
83
+ for(int i = 0; i < len; ++i)
84
+ if(A[i] > B[i])
85
+ return false;
86
+ return true;
87
+ }
88
+
89
+ bool greater_d_array(int len, const double* A, const double* B)
90
+ {
91
+ for(int i = 0; i < len; ++i)
92
+ if(A[i] <= B[i])
93
+ return false;
94
+ return true;
95
+ }
96
+
97
+ bool less_d_array(int len, const double* A, const double* B)
98
+ {
99
+ for(int i = 0; i < len; ++i)
100
+ if(A[i] >= B[i])
101
+ return false;
102
+ return true;
103
+ }
104
+
81
105
  bool zero_d_array(int len, const double* A)
82
106
  {
83
107
  for(int i = 0; i < len; ++i)
@@ -15,6 +15,9 @@ void sub_d_arrays_to_first(int len, double* dif, const double* sub);
15
15
  bool equal_d_arrays(int len, const double* A, const double* B);
16
16
  void abs_d_array(int len, const double* A, double* B);
17
17
  bool greater_or_equal_d_array(int len, const double* A, const double* B);
18
+ bool less_or_equal_d_array(int len, const double* A, const double* B);
19
+ bool greater_d_array(int len, const double* A, const double* B);
20
+ bool less_d_array(int len, const double* A, const double* B);
18
21
  bool zero_d_array(int len, const double* A);
19
22
  void swap_d_arrays(int len, double* A, double* B);
20
23
  void round_d_array(int len, const double* Input, double* Output, int acc);
@@ -2,6 +2,7 @@
2
2
 
3
3
  VALUE fm_eTypeError;
4
4
  VALUE fm_eIndexError;
5
+ VALUE fm_eFrozenError;
5
6
 
6
7
  double raise_rb_value_to_double(VALUE v)
7
8
  {
@@ -40,4 +41,5 @@ void init_fm_errors()
40
41
 
41
42
  fm_eTypeError = rb_define_class_under(mod, "TypeError", rb_eTypeError);
42
43
  fm_eIndexError = rb_define_class_under(mod, "IndexError", rb_eIndexError);
44
+ fm_eFrozenError = rb_define_class_under(mod, "FrozenError", rb_eFrozenError);
43
45
  }
@@ -5,6 +5,7 @@
5
5
 
6
6
  extern VALUE fm_eTypeError;
7
7
  extern VALUE fm_eIndexError;
8
+ extern VALUE fm_eFrozenError;
8
9
 
9
10
  // convert ruby value to double or raise an error if this is not possible
10
11
  double raise_rb_value_to_double(VALUE v);
@@ -0,0 +1,97 @@
1
+ #include "LUPDecomposition/c_lup.h"
2
+ #include "Helper/c_array_operations.h"
3
+
4
+ void c_lup_l(int n, const double* LUP, double* L)
5
+ {
6
+ for(int i = 0; i < n; ++i)
7
+ {
8
+ double* l_line = L + n * i;
9
+ const double* lup_line = LUP + n * i;
10
+ for(int j = 0; j < n; ++j)
11
+ {
12
+ if(i < j)
13
+ l_line[j] = 0;
14
+ else if(i == j)
15
+ l_line[j] = 1;
16
+ else
17
+ l_line[j] = lup_line[j];
18
+ }
19
+ }
20
+ }
21
+
22
+ void c_lup_u(int n, const double* LUP, double* U)
23
+ {
24
+ for(int i = 0; i < n; ++i)
25
+ {
26
+ double* u_line = U + n * i;
27
+ const double* lup_line = LUP + n * i;
28
+ for(int j = 0; j < n; ++j)
29
+ {
30
+ if(i > j)
31
+ u_line[j] = 0;
32
+ else
33
+ u_line[j] = lup_line[j];
34
+ }
35
+ }
36
+ }
37
+
38
+ void c_lup_p(int n, const int* prm, double* P)
39
+ {
40
+ for(int i = 0; i < n; ++i)
41
+ {
42
+ double* p_line = P + n * i;
43
+ int current = prm[i];
44
+ for(int j = 0; j < current; ++j)
45
+ p_line[j] = 0;
46
+ p_line[current] = 1;
47
+ for(int j = current + 1; j < n; ++j)
48
+ p_line[j] = 0;
49
+ }
50
+ }
51
+
52
+ double c_lup_determinant(int n, double* LUP, int sign)
53
+ {
54
+ double res = sign;
55
+ for(int i = 0; i < n; ++i)
56
+ res *= LUP[i + i * n];
57
+ return res;
58
+ }
59
+
60
+ void c_lup_apply_permutation(int m, int n, const double* A, const int* permutation, double* R)
61
+ {
62
+ for(int i = 0; i < n; ++i)
63
+ copy_d_array(m, A + m * permutation[i], R + m * i);
64
+ }
65
+
66
+ void c_lup_solve(int m, int n, const double* lp, const double* B, const int* permutation, double* R)
67
+ {
68
+ c_lup_apply_permutation(m, n, B, permutation, R);
69
+
70
+ for(int k = 0; k < n; ++k)
71
+ for(int i = k + 1; i < n; ++i)
72
+ {
73
+ double* line = R + i * m;
74
+ int mul = lp[i * n + k];
75
+
76
+ for(int j = 0; j < m; ++j)
77
+ line[j] -= line[j] * mul;
78
+ }
79
+
80
+ for(int k = n - 1; k >= 0; --k)
81
+ {
82
+ double* line = R + k * m;
83
+ int div = lp[k * n + k];
84
+
85
+ for(int j = 0; j < m; ++j)
86
+ line[j] /= div;
87
+
88
+ for(int i = 0; i < k; ++i)
89
+ {
90
+ double* line_out = R + i * m;
91
+ int mul = lp[i * n + k];
92
+
93
+ for(int j = 0; j < m; ++j)
94
+ line_out[j] -= line[j] * mul;
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,22 @@
1
+ #ifndef FAST_MATRIX_MATRIX_C_LUPDECOMPOSITION_H
2
+ #define FAST_MATRIX_MATRIX_C_LUPDECOMPOSITION_H 1
3
+
4
+ #include <stdbool.h>
5
+
6
+ struct lupdecomposition
7
+ {
8
+ int n;
9
+ double* data;
10
+ int* permutation;
11
+ int pivot_sign;
12
+ bool singular;
13
+ };
14
+
15
+ double c_lup_determinant(int n, double* LUP, int sign);
16
+
17
+ void c_lup_l(int n, const double* LUP, double* L);
18
+ void c_lup_u(int n, const double* LUP, double* U);
19
+ void c_lup_p(int n, const int* prm, double* P);
20
+ void c_lup_solve(int m, int n, const double* lp, const double* B, const int* permutation, double* R);
21
+
22
+ #endif /* FAST_MATRIX_MATRIX_C_LUPDECOMPOSITION_H */
@@ -0,0 +1,14 @@
1
+ #ifndef FAST_MATRIX_LUPDECOMPOSITION_HELPER_H
2
+ #define FAST_MATRIX_LUPDECOMPOSITION_HELPER_H 1
3
+
4
+ #include "ruby.h"
5
+ #include "Matrix/c_matrix.h"
6
+
7
+ inline struct lupdecomposition* get_lup_from_rb_value(VALUE lp)
8
+ {
9
+ struct lupdecomposition* data;
10
+ TypedData_Get_Struct(lp, struct lupdecomposition, &lup_type, data);
11
+ return data;
12
+ }
13
+
14
+ #endif /* FAST_MATRIX_LUPDECOMPOSITION_HELPER_H */
@@ -0,0 +1,124 @@
1
+ #include "LUPDecomposition/lup.h"
2
+ #include "LUPDecomposition/c_lup.h"
3
+ #include "LUPDecomposition/helper.h"
4
+ #include "Matrix/matrix.h"
5
+ #include "Matrix/helper.h"
6
+ #include "Helper/errors.h"
7
+
8
+ VALUE cLUPDecomposition;
9
+
10
+ void lup_free(void* data);
11
+ size_t lup_size(const void* data);
12
+
13
+ const rb_data_type_t lup_type =
14
+ {
15
+ .wrap_struct_name = "lupdecomposition",
16
+ .function =
17
+ {
18
+ .dmark = NULL,
19
+ .dfree = lup_free,
20
+ .dsize = lup_size,
21
+ },
22
+ .data = NULL,
23
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
24
+ };
25
+
26
+ void lup_free(void* data)
27
+ {
28
+ free(((*(struct lupdecomposition*)data)).data);
29
+ free(((*(struct lupdecomposition*)data)).permutation);
30
+ free(data);
31
+ }
32
+
33
+ size_t lup_size(const void* data)
34
+ {
35
+ return sizeof(struct lupdecomposition);
36
+ }
37
+
38
+ VALUE lup_alloc(VALUE self)
39
+ {
40
+ struct lupdecomposition* lp = malloc(sizeof(struct lupdecomposition));
41
+ lp->data = NULL;
42
+ lp->permutation = NULL;
43
+ lp->pivot_sign = 1;
44
+ lp->singular = false;
45
+ return TypedData_Wrap_Struct(self, &lup_type, lp);
46
+ }
47
+
48
+ VALUE lup_l(VALUE self)
49
+ {
50
+ struct lupdecomposition* lp = get_lup_from_rb_value(self);
51
+ MAKE_MATRIX_AND_RB_VALUE(R, result, lp->n, lp->n);
52
+ c_lup_l(lp->n, lp->data, R->data);
53
+ return result;
54
+ }
55
+
56
+ VALUE lup_u(VALUE self)
57
+ {
58
+ struct lupdecomposition* lp = get_lup_from_rb_value(self);
59
+ MAKE_MATRIX_AND_RB_VALUE(R, result, lp->n, lp->n);
60
+ c_lup_u(lp->n, lp->data, R->data);
61
+ return result;
62
+ }
63
+
64
+ VALUE lup_p(VALUE self)
65
+ {
66
+ struct lupdecomposition* lp = get_lup_from_rb_value(self);
67
+ MAKE_MATRIX_AND_RB_VALUE(R, result, lp->n, lp->n);
68
+ c_lup_p(lp->n, lp->permutation, R->data);
69
+ return result;
70
+ }
71
+
72
+ VALUE lup_determinant(VALUE self)
73
+ {
74
+ struct lupdecomposition* lp = get_lup_from_rb_value(self);
75
+ return DBL2NUM(c_lup_determinant(lp->n, lp->data, lp->pivot_sign));
76
+ }
77
+
78
+ VALUE lup_singular(VALUE self)
79
+ {
80
+ struct lupdecomposition* lp = get_lup_from_rb_value(self);
81
+ if(lp->singular)
82
+ return Qtrue;
83
+ return Qfalse;
84
+ }
85
+
86
+ VALUE lup_pivots(VALUE self)
87
+ {
88
+ struct lupdecomposition* lp = get_lup_from_rb_value(self);
89
+ VALUE* v = malloc(lp->n * sizeof(VALUE));
90
+ for(int i = 0; i < lp->n; ++i)
91
+ v[i] = INT2NUM(lp->permutation[i]);
92
+ VALUE res = rb_ary_new_from_values(lp->n, v);
93
+ free(v);
94
+ return res;
95
+ }
96
+
97
+ VALUE lup_solve(VALUE self, VALUE mtrx)
98
+ {
99
+ raise_check_rbasic(mtrx, cMatrix, "matrix");
100
+ struct lupdecomposition* lp = get_lup_from_rb_value(self);
101
+ struct matrix* M = get_matrix_from_rb_value(mtrx);
102
+ if(lp->singular)
103
+ rb_raise(fm_eIndexError, "Matrix is singular");
104
+ if(lp->n != M->n)
105
+ rb_raise(fm_eIndexError, "Columns of different size");
106
+
107
+ MAKE_MATRIX_AND_RB_VALUE(C, result, M->m, lp->n);
108
+ c_lup_solve(M->m, lp->n, lp->data, M->data, lp->permutation, C->data);
109
+ return result;
110
+ }
111
+
112
+ void init_fm_lup()
113
+ {
114
+ cLUPDecomposition = rb_define_class_under(cMatrix, "LUPDecomposition", rb_cData);
115
+ rb_define_alloc_func(cLUPDecomposition, lup_alloc);
116
+
117
+ rb_define_method(cLUPDecomposition, "l", lup_l, 0);
118
+ rb_define_method(cLUPDecomposition, "u", lup_u, 0);
119
+ rb_define_method(cLUPDecomposition, "p", lup_p, 0);
120
+ rb_define_method(cLUPDecomposition, "det", lup_determinant, 0);
121
+ rb_define_method(cLUPDecomposition, "singular?", lup_singular, 0);
122
+ rb_define_method(cLUPDecomposition, "pivots", lup_pivots, 0);
123
+ rb_define_method(cLUPDecomposition, "solve", lup_solve, 1);
124
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef FAST_MATRIX_LUPDECOMPOSITION_H
2
+ #define FAST_MATRIX_LUPDECOMPOSITION_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ extern VALUE cLUPDecomposition;
7
+ extern const rb_data_type_t lup_type;
8
+ void init_fm_lup();
9
+
10
+ #endif /* FAST_MATRIX_LUPDECOMPOSITION_H */
@@ -1,4 +1,5 @@
1
1
  #include "c_matrix.h"
2
+ #include "Helper/c_array_operations.h"
2
3
 
3
4
  // in - matrix m x n
4
5
  // out - matrix n x m
@@ -604,3 +605,133 @@ bool c_matrix_inverse(int n, const double* A, double* B)
604
605
  free(M);
605
606
  return true;
606
607
  }
608
+
609
+ bool c_matrix_adjugate(int n, const double* A, double* B)
610
+ {
611
+ if(!c_matrix_inverse(n, A, B))
612
+ return false;
613
+ double d = c_matrix_determinant(n, A);
614
+ multiply_d_array(n * n, B, d);
615
+ return true;
616
+ }
617
+
618
+ void c_matrix_recursive_exponentiation(int n, const double* A, double* B, int d)
619
+ {
620
+ if(d == 2)
621
+ return c_matrix_strassen(n, n, n, A, A, B);
622
+
623
+ double* C = malloc(n * n * sizeof(double));
624
+
625
+ if(d == 3)
626
+ {
627
+ c_matrix_strassen(n, n, n, A, A, C);
628
+ c_matrix_strassen(n, n, n, A, C, B);
629
+ free(C);
630
+ return;
631
+ }
632
+
633
+ c_matrix_recursive_exponentiation(n, A, C, d / 2);
634
+
635
+ if(d % 2 == 0)
636
+ {
637
+ c_matrix_strassen(n, n, n, C, C, B);
638
+ free(C);
639
+ return;
640
+ }
641
+
642
+ double* D = malloc(n * n * sizeof(double));
643
+
644
+ c_matrix_strassen(n, n, n, C, C, D);
645
+ c_matrix_strassen(n, n, n, A, D, B);
646
+ free(C);
647
+ free(D);
648
+ }
649
+
650
+ bool c_matrix_exponentiation(int m, int n, const double* A, double* B, int d)
651
+ {
652
+ if(d == 1)
653
+ {
654
+ copy_d_array(m * n, A, B);
655
+ return true;
656
+ }
657
+
658
+ if(m != n)
659
+ return false;
660
+
661
+ if(d == 0)
662
+ {
663
+ c_matrix_shift_identity(n, B, n);
664
+ return true;
665
+ }
666
+
667
+ if(d > 0)
668
+ {
669
+ c_matrix_recursive_exponentiation(n, A, B, d);
670
+ return true;
671
+ }
672
+
673
+ if(d == -1)
674
+ {
675
+ c_matrix_inverse(n, A, B);
676
+ return true;
677
+ }
678
+
679
+ double* C = malloc(n * n * sizeof(double));
680
+ c_matrix_inverse(n, A, C);
681
+ c_matrix_recursive_exponentiation(n, C, B, -d);
682
+ free(C);
683
+
684
+ return true;
685
+ }
686
+
687
+ void c_matrix_fill_range_array(int n, int* V)
688
+ {
689
+ for(int i = 0; i < n; ++i)
690
+ V[i] = i;
691
+ }
692
+
693
+ void c_matrix_lup(int n, const double* A, double* LU, int* V, int* sign, bool* singular)
694
+ {
695
+ copy_d_array(n * n, A, LU);
696
+ c_matrix_fill_range_array(n, V);
697
+ *sign = 1;
698
+ *singular = false;
699
+
700
+ for(int i = 0; i < n; ++i)
701
+ {
702
+ double* line = LU + n * i;
703
+ double current = 0;
704
+ int swap_line = -1;
705
+ for(int j = i; j < n; ++j)
706
+ if(fabs(LU[j * n + i]) > current)
707
+ {
708
+ swap_line = j;
709
+ current = fabs(LU[j * n + i]);
710
+ }
711
+
712
+ if(swap_line == -1)
713
+ {
714
+ *singular = true;
715
+ continue;
716
+ }
717
+
718
+ if(swap_line != i)
719
+ {
720
+ swap_d_arrays(n, LU + swap_line * n, line);
721
+ int buf = V[i];
722
+ V[i] = V[swap_line];
723
+ V[swap_line] = buf;
724
+ *sign = -*sign;
725
+ }
726
+
727
+ current = line[i];
728
+ for(int j = i + 1; j < n; ++j)
729
+ {
730
+ double* w_line = LU + j * n;
731
+ w_line[i] = w_line[i] / current;
732
+ double start = w_line[i];
733
+ for(int k = i + 1; k < n; ++k)
734
+ w_line[k] -= start * line[k];
735
+ }
736
+ }
737
+ }