fast_matrix 0.1.66 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.dockerignore +0 -1
- data/.travis.yml +2 -1
- data/README.md +3 -8
- data/ext/fast_matrix/{c_array_opeartions.c → Helper/c_array_opeartions.c} +39 -1
- data/ext/fast_matrix/{c_array_operations.h → Helper/c_array_operations.h} +6 -1
- data/ext/fast_matrix/{errors.c → Helper/errors.c} +8 -2
- data/ext/fast_matrix/{errors.h → Helper/errors.h} +3 -1
- data/ext/fast_matrix/Matrix/c_matrix.c +606 -0
- data/ext/fast_matrix/Matrix/c_matrix.h +49 -0
- data/ext/fast_matrix/Matrix/errors.h +28 -0
- data/ext/fast_matrix/Matrix/helper.h +27 -0
- data/ext/fast_matrix/Matrix/matrix.c +633 -0
- data/ext/fast_matrix/Matrix/matrix.h +11 -0
- data/ext/fast_matrix/Vector/c_vector.c +97 -0
- data/ext/fast_matrix/Vector/c_vector.h +24 -0
- data/ext/fast_matrix/Vector/errors.h +14 -0
- data/ext/fast_matrix/Vector/helper.h +26 -0
- data/ext/fast_matrix/Vector/vector.c +476 -0
- data/ext/fast_matrix/{vector.h → Vector/vector.h} +0 -10
- data/ext/fast_matrix/c_include.c +8 -0
- data/ext/fast_matrix/fast_matrix.h +3 -3
- data/fast_matrix.gemspec +1 -1
- data/lib/fast_matrix/version.rb +1 -1
- data/lib/matrix/constructors.rb +0 -63
- data/lib/matrix/matrix.rb +105 -4
- data/lib/vector/constructors.rb +5 -4
- data/lib/vector/vector.rb +29 -0
- metadata +21 -12
- data/ext/fast_matrix/matrix.c +0 -678
- data/ext/fast_matrix/matrix.h +0 -28
- data/ext/fast_matrix/vector.c +0 -277
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0e98406e186191f8308eeca9cc81293343f44fd4a6e97559c6b4e3ce2d8b0b7
|
4
|
+
data.tar.gz: a6e2c1b4f49e62c76e27e23df7a358ca22c927099868f990488e5ea5c1ca21e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 596d0c7a7bec078b328968e0a1a0c20e83076215594807395e2323eabf239fa5a61d88cde3564219b28f8520f97d40e06d34e39e5aea8ec0db0c08befddc2b39
|
7
|
+
data.tar.gz: a53d3c85372d7f9273cdee68789a2fadecae44f05f2f6244c6661970de890b246e81d44800354964ea32cf5f80292f2464ca7fb6b2b30683a90f6fcd3cdeba74
|
data/.dockerignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# FastMatrix
|
6
6
|
|
7
|
-
Ruby wrapper around C matrices implementation written as exercise by
|
7
|
+
Ruby wrapper around C matrices implementation written as exercise by MMCS students.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
@@ -22,14 +22,9 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
$ gem install fast_matrix
|
24
24
|
|
25
|
-
## Usage
|
25
|
+
## Usage and documentation
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
### Differences with the standard matrix
|
30
|
-
* Supported only double values
|
31
|
-
* Can't be empty
|
32
|
-
* Some faster
|
27
|
+
See our [GitHub Wiki](https://github.com/mmcs-ruby/fast_matrix/wiki).
|
33
28
|
|
34
29
|
## Development
|
35
30
|
|
@@ -1,5 +1,6 @@
|
|
1
|
-
#include "c_array_operations.h"
|
1
|
+
#include "Helper/c_array_operations.h"
|
2
2
|
#include "math.h"
|
3
|
+
#include "stdlib.h"
|
3
4
|
|
4
5
|
void fill_d_array(int len, double* a, double v)
|
5
6
|
{
|
@@ -13,6 +14,18 @@ void multiply_d_array(int len, double* a, double v)
|
|
13
14
|
a[i] *= v;
|
14
15
|
}
|
15
16
|
|
17
|
+
void multiply_elems_d_array_to_result(int len, const double* a, const double* b, double* res)
|
18
|
+
{
|
19
|
+
for(int i = 0; i < len; ++i)
|
20
|
+
res[i] = a[i] * b[i];
|
21
|
+
}
|
22
|
+
|
23
|
+
void multiply_d_array_to_result(int len, const double* a, double v, double* res)
|
24
|
+
{
|
25
|
+
for(int i = 0; i < len; ++i)
|
26
|
+
res[i] = a[i] * v;
|
27
|
+
}
|
28
|
+
|
16
29
|
void copy_d_array(int len, const double* input, double* output)
|
17
30
|
{
|
18
31
|
for(int i = 0; i < len; ++i)
|
@@ -64,3 +77,28 @@ bool greater_or_equal_d_array(int len, const double* A, const double* B)
|
|
64
77
|
return false;
|
65
78
|
return true;
|
66
79
|
}
|
80
|
+
|
81
|
+
bool zero_d_array(int len, const double* A)
|
82
|
+
{
|
83
|
+
for(int i = 0; i < len; ++i)
|
84
|
+
if(A[i] != 0)
|
85
|
+
return false;
|
86
|
+
return true;
|
87
|
+
}
|
88
|
+
|
89
|
+
void swap_d_arrays(int len, double* A, double* B)
|
90
|
+
{
|
91
|
+
for(int i = 0; i < len; ++i)
|
92
|
+
{
|
93
|
+
double buf = A[i];
|
94
|
+
A[i] = B[i];
|
95
|
+
B[i] = buf;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
void round_d_array(int len, const double* Input, double* Output, int acc)
|
100
|
+
{
|
101
|
+
double d = pow(10, acc);
|
102
|
+
for(int i = 0; i < len; ++i)
|
103
|
+
Output[i] = roundf(Input[i] * d) / d;
|
104
|
+
}
|
@@ -1,10 +1,12 @@
|
|
1
1
|
#ifndef C_ARRAY_OPERATIONS
|
2
2
|
#define C_ARRAY_OPERATIONS
|
3
3
|
|
4
|
-
#include
|
4
|
+
#include <stdbool.h>
|
5
5
|
|
6
6
|
void fill_d_array(int len, double* a, double v);
|
7
|
+
void multiply_elems_d_array_to_result(int len, const double* a, const double* b, double* res);
|
7
8
|
void multiply_d_array(int len, double* a, double v);
|
9
|
+
void multiply_d_array_to_result(int len, const double* a, double v, double* res);
|
8
10
|
void copy_d_array(int len, const double* input, double* output);
|
9
11
|
void add_d_arrays_to_result(int len, const double* a1, const double* a2, double* result);
|
10
12
|
void add_d_arrays_to_first(int len, double* sum, const double* added);
|
@@ -13,5 +15,8 @@ void sub_d_arrays_to_first(int len, double* dif, const double* sub);
|
|
13
15
|
bool equal_d_arrays(int len, const double* A, const double* B);
|
14
16
|
void abs_d_array(int len, const double* A, double* B);
|
15
17
|
bool greater_or_equal_d_array(int len, const double* A, const double* B);
|
18
|
+
bool zero_d_array(int len, const double* A);
|
19
|
+
void swap_d_arrays(int len, double* A, double* B);
|
20
|
+
void round_d_array(int len, const double* Input, double* Output, int acc);
|
16
21
|
|
17
22
|
#endif /*C_ARRAY_OPERATIONS*/
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#include "errors.h"
|
1
|
+
#include "Helper/errors.h"
|
2
2
|
|
3
3
|
VALUE fm_eTypeError;
|
4
4
|
VALUE fm_eIndexError;
|
@@ -28,10 +28,16 @@ void raise_check_range(int v, int min, int max)
|
|
28
28
|
rb_raise(fm_eIndexError, "Index out of range");
|
29
29
|
}
|
30
30
|
|
31
|
+
void raise_check_rbasic(VALUE v, VALUE rBasic, const char* rbasic_name)
|
32
|
+
{
|
33
|
+
if(RBASIC_CLASS(v) != rBasic)
|
34
|
+
rb_raise(fm_eTypeError, "Expected class %s", rbasic_name);
|
35
|
+
}
|
36
|
+
|
31
37
|
void init_fm_errors()
|
32
38
|
{
|
33
39
|
VALUE mod = rb_define_module("FastMatrix");
|
34
40
|
|
35
41
|
fm_eTypeError = rb_define_class_under(mod, "TypeError", rb_eTypeError);
|
36
42
|
fm_eIndexError = rb_define_class_under(mod, "IndexError", rb_eIndexError);
|
37
|
-
}
|
43
|
+
}
|
@@ -12,7 +12,9 @@ double raise_rb_value_to_double(VALUE v);
|
|
12
12
|
int raise_rb_value_to_int(VALUE v);
|
13
13
|
// check if the value is in range and raise an error if not
|
14
14
|
void raise_check_range(int v, int min, int max);
|
15
|
+
// check if the basic class of value is rBasic and raise an error if not
|
16
|
+
void raise_check_rbasic(VALUE v, VALUE rBasic, const char* rbasic_name);
|
15
17
|
|
16
18
|
void init_fm_errors();
|
17
19
|
|
18
|
-
#endif /* FAST_MATRIX_ERRORS_H */
|
20
|
+
#endif /* FAST_MATRIX_ERRORS_H */
|
@@ -0,0 +1,606 @@
|
|
1
|
+
#include "c_matrix.h"
|
2
|
+
|
3
|
+
// in - matrix m x n
|
4
|
+
// out - matrix n x m
|
5
|
+
void c_matrix_transpose(int m, int n, const double* in, double* out)
|
6
|
+
{
|
7
|
+
for(int i = 0; i < m; ++i)
|
8
|
+
for(int j = 0; j < n; ++j)
|
9
|
+
out[j + n * i] = in[i + m * j];
|
10
|
+
}
|
11
|
+
|
12
|
+
// A - matrix k x n
|
13
|
+
// B - matrix m x k
|
14
|
+
// C - matrix m x n
|
15
|
+
void c_matrix_multiply(int n, int k, int m, const double* A, const double* B, double* C)
|
16
|
+
{
|
17
|
+
fill_d_array(m * n, C, 0);
|
18
|
+
|
19
|
+
for(int j = 0; j < n; ++j)
|
20
|
+
{
|
21
|
+
double* p_c = C + m * j;
|
22
|
+
const double* p_a = A + k * j;
|
23
|
+
|
24
|
+
for(int t = 0; t < k; ++t)
|
25
|
+
{
|
26
|
+
const double* p_b = B + m * t;
|
27
|
+
double d_a = p_a[t];
|
28
|
+
if(d_a != 0)
|
29
|
+
for(int i = 0; i < m; ++i)
|
30
|
+
p_c[i] += d_a * p_b[i];
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
// M - matrix m x n
|
36
|
+
// V - vector m
|
37
|
+
// R - vector n
|
38
|
+
void c_matrix_vector_multiply(int n, int m, const double* M, const double* V, double* R)
|
39
|
+
{
|
40
|
+
fill_d_array(n, R, 0);
|
41
|
+
|
42
|
+
for(int j = 0; j < n; ++j)
|
43
|
+
{
|
44
|
+
const double* p_m = M + m * j;
|
45
|
+
for(int i = 0; i < m; ++i)
|
46
|
+
R[j] += V[i] * p_m[i];
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
// A - matrix k x n
|
52
|
+
// B - matrix m x k
|
53
|
+
// C - matrix m x n
|
54
|
+
void strassen_iteration(int n, int k, int m, const double* A, const double* B, double* C, int s_a, int s_b, int s_c)
|
55
|
+
{
|
56
|
+
for(int j = 0; j < n; ++j)
|
57
|
+
{
|
58
|
+
double* p_c = C + s_c * j;
|
59
|
+
const double* p_a = A + s_a * j;
|
60
|
+
|
61
|
+
for(int t = 0; t < k; ++t)
|
62
|
+
{
|
63
|
+
const double* p_b = B + s_b * t;
|
64
|
+
double d_a = p_a[t];
|
65
|
+
for(int i = 0; i < m; ++i)
|
66
|
+
p_c[i] += d_a * p_b[i];
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
bool check_strassen(int m, int n, int k)
|
72
|
+
{
|
73
|
+
return n > 2 && m > 2 && k > 2 && (double)m * (double)n * (double)k > 1000000;
|
74
|
+
}
|
75
|
+
|
76
|
+
// A B
|
77
|
+
// [x x x] [x x x]
|
78
|
+
// [x x x] => [x x x]
|
79
|
+
// [x x x] [x x x]
|
80
|
+
void strassen_copy(int m, int n, const double* A, double* B, int s_a, int s_b)
|
81
|
+
{
|
82
|
+
for(int i = 0; i < n; ++i)
|
83
|
+
{
|
84
|
+
const double* p_A = A + i * s_a;
|
85
|
+
double* p_B = B + i * s_b;
|
86
|
+
for(int j = 0; j < m; ++j)
|
87
|
+
p_B[j] = p_A[j];
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
// if right = false and down = false | if right = true and down = false:
|
92
|
+
// A B | A B
|
93
|
+
// [x x x] [x x x] | [x x x] [x x x 0]
|
94
|
+
// [x x x] => [x x x] | [x x x] => [x x x 0]
|
95
|
+
// [x x x] [x x x] | [x x x] [x x x 0]
|
96
|
+
// |
|
97
|
+
// if right = false and down = true | if right = true and down = true:
|
98
|
+
// A B | A B
|
99
|
+
// [x x x] [x x x] | [x x x] [x x x 0]
|
100
|
+
// [x x x] => [x x x] | [x x x] => [x x x 0]
|
101
|
+
// [x x x] [x x x] | [x x x] [x x x 0]
|
102
|
+
// [0 0 0] | [0 0 0 0]
|
103
|
+
void strassen_copy_with_zero(int m, int n, const double* A, double* B, int s_a, int s_b, bool right, bool down)
|
104
|
+
{
|
105
|
+
double* p_B;
|
106
|
+
for(int i = 0; i < n; ++i)
|
107
|
+
{
|
108
|
+
const double* p_A = A + i * s_a;
|
109
|
+
p_B = B + i * s_b;
|
110
|
+
for(int j = 0; j < m; ++j)
|
111
|
+
p_B[j] = p_A[j];
|
112
|
+
if(right)
|
113
|
+
p_B[m] = 0;
|
114
|
+
}
|
115
|
+
|
116
|
+
if(down)
|
117
|
+
{
|
118
|
+
p_B = B + n * s_b;
|
119
|
+
for(int j = 0; j < m; ++j)
|
120
|
+
p_B[j] = 0;
|
121
|
+
if(right)
|
122
|
+
p_B[m] = 0;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
void strassen_sum_to_first(int m, int n, double* A, const double* B, int s_a, int s_b)
|
127
|
+
{
|
128
|
+
for(int i = 0; i < n; ++i)
|
129
|
+
{
|
130
|
+
double* p_A = A + i * s_a;
|
131
|
+
const double* p_B = B + i * s_b;
|
132
|
+
for(int j = 0; j < m; ++j)
|
133
|
+
p_A[j] += p_B[j];
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
void strassen_sub_to_first(int m, int n, double* A, const double* B, int s_a, int s_b)
|
138
|
+
{
|
139
|
+
for(int i = 0; i < n; ++i)
|
140
|
+
{
|
141
|
+
double* p_A = A + i * s_a;
|
142
|
+
const double* p_B = B + i * s_b;
|
143
|
+
for(int j = 0; j < m; ++j)
|
144
|
+
p_A[j] -= p_B[j];
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
// A - matrix k x n
|
149
|
+
// B - matrix m x k
|
150
|
+
// C - matrix m x n
|
151
|
+
void c_matrix_strassen(int n, int k, int m, const double* A, const double* B, double* C)
|
152
|
+
{
|
153
|
+
if(!check_strassen(m, n, k))
|
154
|
+
return c_matrix_multiply(n, k, m, A, B, C);
|
155
|
+
|
156
|
+
int k2 = k / 2;
|
157
|
+
int k1 = k - k2;
|
158
|
+
int m2 = m / 2;
|
159
|
+
int m1 = m - m2;
|
160
|
+
int n2 = n / 2;
|
161
|
+
int n1 = n - n2;
|
162
|
+
|
163
|
+
double* termA = malloc(k1 * n1 * sizeof(double));
|
164
|
+
double* termB = malloc(m1 * k1 * sizeof(double));
|
165
|
+
|
166
|
+
double* P1 = malloc(7 * m1 * n1 * sizeof(double));
|
167
|
+
double* P2 = P1 + m1 * n1;
|
168
|
+
double* P3 = P2 + m1 * n1;
|
169
|
+
double* P4 = P3 + m1 * n1;
|
170
|
+
double* P5 = P4 + m1 * n1;
|
171
|
+
double* P6 = P5 + m1 * n1;
|
172
|
+
double* P7 = P6 + m1 * n1;
|
173
|
+
fill_d_array(7 * m1 * n1, P1, 0);
|
174
|
+
|
175
|
+
// -----------P1-----------
|
176
|
+
strassen_copy(k1, n1, A, termA, k, k1);
|
177
|
+
strassen_sum_to_first(k2, n2, termA, A + k1 + k * n1, k1, k);
|
178
|
+
|
179
|
+
strassen_copy(m1, k1, B, termB, m, m1);
|
180
|
+
strassen_sum_to_first(m2, k2, termB, B + m1 + m * k1, m1, m);
|
181
|
+
|
182
|
+
c_matrix_strassen(n1, k1, m1, termA, termB, P1);
|
183
|
+
// -----------P2-----------
|
184
|
+
strassen_copy_with_zero(k1, n2, A + k * n1, termA, k, k1, false, n1 != n2);
|
185
|
+
strassen_sum_to_first(k2, n2, termA, A + k1 + k * n1, k1, k);
|
186
|
+
|
187
|
+
strassen_copy(m1, k1, B, termB, m, m1);
|
188
|
+
|
189
|
+
c_matrix_strassen(n1, k1, m1, termA, termB, P2);
|
190
|
+
// -----------P3-----------
|
191
|
+
strassen_copy(k1, n1, A, termA, k, k1);
|
192
|
+
|
193
|
+
strassen_copy_with_zero(m2, k1, B + m1, termB, m, m1, m1 != m2, false);
|
194
|
+
strassen_sub_to_first(m2, k2, termB, B + m1 + m * k1, m1, m);
|
195
|
+
|
196
|
+
c_matrix_strassen(n1, k1, m1, termA, termB, P3);
|
197
|
+
// -----------P4-----------
|
198
|
+
strassen_copy_with_zero(k2, n2, A + k1 + k * n1, termA, k, k1, k1 != k2, n1 != n2);
|
199
|
+
|
200
|
+
strassen_copy_with_zero(m1, k2, B + m * k1, termB, m, m1, false, k1 != k2);
|
201
|
+
strassen_sub_to_first(m1, k1, termB, B, m1, m);
|
202
|
+
|
203
|
+
c_matrix_strassen(n1, k1, m1, termA, termB, P4);
|
204
|
+
// -----------P5-----------
|
205
|
+
strassen_copy(k1, n1, A, termA, k, k1);
|
206
|
+
strassen_sum_to_first(k2, n1, termA, A + k1, k1, k);
|
207
|
+
|
208
|
+
strassen_copy_with_zero(m2, k2, B + m1 + m * k1, termB, m, m1, m1 != m2, k1 != k2);
|
209
|
+
|
210
|
+
c_matrix_strassen(n1, k1, m1, termA, termB, P5);
|
211
|
+
// -----------P6-----------
|
212
|
+
strassen_copy_with_zero(k1, n2, A + k * n1, termA, k, k1, false, n1 != n2);
|
213
|
+
strassen_sub_to_first(k1, n1, termA, A, k1, k);
|
214
|
+
|
215
|
+
strassen_copy(m1, k1, B, termB, m, m1);
|
216
|
+
strassen_sum_to_first(m2, k1, termB, B + m1, m1, m);
|
217
|
+
|
218
|
+
c_matrix_strassen(n1, k1, m1, termA, termB, P6);
|
219
|
+
// -----------P7-----------
|
220
|
+
strassen_copy_with_zero(k2, n1, A + k1, termA, k, k1, k1 != k2, false);
|
221
|
+
strassen_sub_to_first(k2, n2, termA, A + k1 + k * n1, k1, k);
|
222
|
+
|
223
|
+
strassen_copy_with_zero(m1, k2, B + k1 * m, termB, m, m1, false, k1 != k2);
|
224
|
+
strassen_sum_to_first(m2, k2, termB, B + m1 + m * k1, m1, m);
|
225
|
+
|
226
|
+
c_matrix_strassen(n1, k1, m1, termA, termB, P7);
|
227
|
+
|
228
|
+
// -----------C11-----------
|
229
|
+
double* C11 = C;
|
230
|
+
strassen_copy(m1, n1, P1, C11, m1, m);
|
231
|
+
strassen_sum_to_first(m1, n1, C11, P4, m, m1);
|
232
|
+
strassen_sub_to_first(m1, n1, C11, P5, m, m1);
|
233
|
+
strassen_sum_to_first(m1, n1, C11, P7, m, m1);
|
234
|
+
// -----------C12-----------
|
235
|
+
double* C12 = C + m1;
|
236
|
+
strassen_copy(m2, n1, P3, C12, m1, m);
|
237
|
+
strassen_sum_to_first(m2, n1, C12, P5, m, m1);
|
238
|
+
// -----------C21-----------
|
239
|
+
double* C21 = C + m * n1;
|
240
|
+
strassen_copy(m1, n2, P2, C21, m1, m);
|
241
|
+
strassen_sum_to_first(m1, n2, C21, P4, m, m1);
|
242
|
+
// -----------C22-----------
|
243
|
+
double* C22 = C + m1 + m * n1;
|
244
|
+
strassen_copy(m2, n2, P1, C22, m1, m);
|
245
|
+
strassen_sub_to_first(m2, n2, C22, P2, m, m1);
|
246
|
+
strassen_sum_to_first(m2, n2, C22, P3, m, m1);
|
247
|
+
strassen_sum_to_first(m2, n2, C22, P6, m, m1);
|
248
|
+
|
249
|
+
free(termA);
|
250
|
+
free(termB);
|
251
|
+
free(P1);
|
252
|
+
}
|
253
|
+
|
254
|
+
void c_matrix_hstack(int argc, struct matrix** mtrs, double* C, int m)
|
255
|
+
{
|
256
|
+
for(int i = 0; i < argc; ++i)
|
257
|
+
{
|
258
|
+
struct matrix* M = mtrs[i];
|
259
|
+
// a little misuse of the method
|
260
|
+
strassen_copy(M->m, M->n, M->data, C, M->m, m);
|
261
|
+
C += M->m;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
void c_matrix_column_vector(int m, int n, const double* M, double* V, int idx)
|
266
|
+
{
|
267
|
+
M = M + idx;
|
268
|
+
for(int i = 0; i < n; ++i)
|
269
|
+
{
|
270
|
+
V[i] = *M;
|
271
|
+
M += m;
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
void c_matrix_scalar(int n, double* C, double v)
|
276
|
+
{
|
277
|
+
int ptr = 0;
|
278
|
+
|
279
|
+
for(int i = 0; i < n * n; ++i)
|
280
|
+
{
|
281
|
+
if(i == ptr)
|
282
|
+
{
|
283
|
+
ptr += n + 1;
|
284
|
+
C[i] = v;
|
285
|
+
}else
|
286
|
+
C[i] = 0;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
bool c_matrix_symmetric(int n, const double* C)
|
291
|
+
{
|
292
|
+
for(int i = 0; i < n; ++i)
|
293
|
+
for(int j = i; j < n; ++j)
|
294
|
+
if(C[i + j * n] != C[j + i * n])
|
295
|
+
return false;
|
296
|
+
return true;
|
297
|
+
}
|
298
|
+
|
299
|
+
bool c_matrix_antisymmetric(int n, const double* C)
|
300
|
+
{
|
301
|
+
for(int i = 0; i < n; ++i)
|
302
|
+
for(int j = i; j < n; ++j)
|
303
|
+
if(C[i + j * n] != -C[j + i * n])
|
304
|
+
return false;
|
305
|
+
return true;
|
306
|
+
}
|
307
|
+
|
308
|
+
bool c_matrix_diagonal(int n, const double* C)
|
309
|
+
{
|
310
|
+
int ptr = 0;
|
311
|
+
|
312
|
+
for(int i = 0; i < n * n; ++i)
|
313
|
+
{
|
314
|
+
if(i == ptr)
|
315
|
+
ptr += n + 1;
|
316
|
+
else if(C[i] != 0)
|
317
|
+
return false;
|
318
|
+
}
|
319
|
+
return true;
|
320
|
+
}
|
321
|
+
|
322
|
+
double c_matrix_trace(int n, const double* A)
|
323
|
+
{
|
324
|
+
int sum = 0;
|
325
|
+
for(int i = 0; i < n; ++i)
|
326
|
+
sum += A[i + i * n];
|
327
|
+
return sum;
|
328
|
+
}
|
329
|
+
|
330
|
+
void c_matrix_minor(int m, int n, const double* A, double* B, int m_idx, int n_idx)
|
331
|
+
{
|
332
|
+
for(int j = 0; j < n - 1; ++j)
|
333
|
+
{
|
334
|
+
int j_step = (j >= n_idx) ? 1 : 0;
|
335
|
+
for(int i = 0; i < m - 1; ++i)
|
336
|
+
{
|
337
|
+
int i_step = (i >= m_idx) ? 1 : 0;
|
338
|
+
B[i + j * (m - 1)] = A[(i + i_step) + (j + j_step) * m];
|
339
|
+
}
|
340
|
+
}
|
341
|
+
}
|
342
|
+
|
343
|
+
bool c_matrix_lower_triangular(int n, const double* A)
|
344
|
+
{
|
345
|
+
for(int i = 0; i < n; ++i)
|
346
|
+
{
|
347
|
+
const double* line = A + (i + 1) + n * i;
|
348
|
+
for(int j = 0; j < n - i - 1; ++j)
|
349
|
+
if(line[j] != 0)
|
350
|
+
return false;
|
351
|
+
}
|
352
|
+
return true;
|
353
|
+
}
|
354
|
+
|
355
|
+
bool c_matrix_upper_triangular(int n, const double* A)
|
356
|
+
{
|
357
|
+
for(int i = 1; i < n; ++i)
|
358
|
+
{
|
359
|
+
const double* line = A + n * i;
|
360
|
+
for(int j = 0; j < i; ++j)
|
361
|
+
if(line[j] != 0)
|
362
|
+
return false;
|
363
|
+
}
|
364
|
+
return true;
|
365
|
+
}
|
366
|
+
|
367
|
+
bool c_matrix_permutation(int n, const double* A)
|
368
|
+
{
|
369
|
+
bool* f = malloc(n * sizeof(bool));
|
370
|
+
for(int i = 0; i < n; ++i)
|
371
|
+
f[i] = false;
|
372
|
+
|
373
|
+
bool result;
|
374
|
+
for(int i = 0; i < n; ++i)
|
375
|
+
{
|
376
|
+
const double* line = A + n * i;
|
377
|
+
result = false;
|
378
|
+
for(int j = 0; j < n; ++j)
|
379
|
+
{
|
380
|
+
double v = line[j];
|
381
|
+
if(v == 0)
|
382
|
+
continue;
|
383
|
+
|
384
|
+
if(v != 1 || result || f[j])
|
385
|
+
{
|
386
|
+
result = false;
|
387
|
+
break;
|
388
|
+
}
|
389
|
+
|
390
|
+
result = f[j] = true;
|
391
|
+
}
|
392
|
+
if(!result)
|
393
|
+
break;
|
394
|
+
}
|
395
|
+
|
396
|
+
if(result)
|
397
|
+
for(int i = 0; i < n; ++i)
|
398
|
+
if(!f[i])
|
399
|
+
{
|
400
|
+
result = false;
|
401
|
+
break;
|
402
|
+
}
|
403
|
+
free(f);
|
404
|
+
return result;
|
405
|
+
}
|
406
|
+
|
407
|
+
bool c_matrix_identity(int n, const double* A)
|
408
|
+
{
|
409
|
+
for(int i = 0; i < n; ++i)
|
410
|
+
{
|
411
|
+
const double* p_a = A + i * n;
|
412
|
+
for(int j = 0; j < n; ++j)
|
413
|
+
if(i == j)
|
414
|
+
{ if(p_a[j] != 1) return false; }
|
415
|
+
else
|
416
|
+
{ if(p_a[j] != 0) return false; }
|
417
|
+
}
|
418
|
+
return true;
|
419
|
+
}
|
420
|
+
|
421
|
+
bool c_matrix_equal_by_m(int argc, struct matrix** mtrs)
|
422
|
+
{
|
423
|
+
int m = mtrs[0]->m;
|
424
|
+
for(int i = 1; i < argc; ++i)
|
425
|
+
if(m != mtrs[i]->m)
|
426
|
+
return false;
|
427
|
+
return true;
|
428
|
+
}
|
429
|
+
|
430
|
+
bool c_matrix_equal_by_n(int argc, struct matrix** mtrs)
|
431
|
+
{
|
432
|
+
int n = mtrs[0]->n;
|
433
|
+
for(int i = 1; i < argc; ++i)
|
434
|
+
if(n != mtrs[i]->n)
|
435
|
+
return false;
|
436
|
+
return true;
|
437
|
+
}
|
438
|
+
|
439
|
+
int c_matrix_sum_by_m(int argc, struct matrix** mtrs)
|
440
|
+
{
|
441
|
+
int sum = 0;
|
442
|
+
for(int i = 0; i < argc; ++i)
|
443
|
+
sum += mtrs[i]->m;
|
444
|
+
return sum;
|
445
|
+
}
|
446
|
+
|
447
|
+
int c_matrix_sum_by_n(int argc, struct matrix** mtrs)
|
448
|
+
{
|
449
|
+
int sum = 0;
|
450
|
+
for(int i = 0; i < argc; ++i)
|
451
|
+
sum += mtrs[i]->n;
|
452
|
+
return sum;
|
453
|
+
}
|
454
|
+
|
455
|
+
void c_matrix_vstack(int argc, struct matrix** mtrs, double* C)
|
456
|
+
{
|
457
|
+
for(int i = 0; i < argc; ++i)
|
458
|
+
{
|
459
|
+
struct matrix* M = mtrs[i];
|
460
|
+
int len = M->m * M->n;
|
461
|
+
copy_d_array(len, M->data, C);
|
462
|
+
C += len;
|
463
|
+
}
|
464
|
+
}
|
465
|
+
|
466
|
+
int c_matrix_rank(int m, int n, const double* C)
|
467
|
+
{
|
468
|
+
double* A = malloc(sizeof(double) * m * n);
|
469
|
+
copy_d_array(m * n, C, A);
|
470
|
+
|
471
|
+
int i = 0;
|
472
|
+
int c_ptr = 0;
|
473
|
+
while(i < n && c_ptr < m)
|
474
|
+
{
|
475
|
+
double* line = A + c_ptr + i * m;
|
476
|
+
double val = line[0];
|
477
|
+
|
478
|
+
if(val == 0)
|
479
|
+
for(int j = i + 1; j < n; ++j)
|
480
|
+
if(A[c_ptr + j * m] != 0)
|
481
|
+
{
|
482
|
+
double* buf = A + c_ptr + j * m;
|
483
|
+
swap_d_arrays(m - c_ptr, buf, line);
|
484
|
+
val = line[0];
|
485
|
+
break;
|
486
|
+
}
|
487
|
+
|
488
|
+
if(val == 0)
|
489
|
+
{
|
490
|
+
++c_ptr;
|
491
|
+
continue;
|
492
|
+
}
|
493
|
+
|
494
|
+
for(int j = i + 1; j < n; ++j)
|
495
|
+
{
|
496
|
+
double* target = A + c_ptr + j * m;
|
497
|
+
double mul = target[0];
|
498
|
+
if(mul == 0)
|
499
|
+
continue;
|
500
|
+
for(int k = 1; k < m - c_ptr; ++k)
|
501
|
+
target[k] = val * target[k] - mul * line[k];
|
502
|
+
}
|
503
|
+
++c_ptr;
|
504
|
+
++i;
|
505
|
+
}
|
506
|
+
free(A);
|
507
|
+
return i;
|
508
|
+
}
|
509
|
+
|
510
|
+
double c_matrix_determinant(int n, const double* A)
|
511
|
+
{
|
512
|
+
double* M = malloc(n * n * sizeof(double));
|
513
|
+
double det = 1;
|
514
|
+
copy_d_array(n * n, A, M);
|
515
|
+
|
516
|
+
for(int i = 0; i < n; ++i)
|
517
|
+
{
|
518
|
+
double* line_p = M + i + i * n;
|
519
|
+
double current = *line_p;
|
520
|
+
|
521
|
+
if(current == 0)
|
522
|
+
for(int j = i + 1; j < n; ++j)
|
523
|
+
if(M[i + j * n] != 0)
|
524
|
+
{
|
525
|
+
double* buf = M + i + j * n;
|
526
|
+
swap_d_arrays(n - i, buf, line_p);
|
527
|
+
current = line_p[0];
|
528
|
+
det *= -1;
|
529
|
+
}
|
530
|
+
|
531
|
+
if(current == 0)
|
532
|
+
{
|
533
|
+
free(M);
|
534
|
+
return 0;
|
535
|
+
}
|
536
|
+
|
537
|
+
det *= current;
|
538
|
+
|
539
|
+
for(int j = i + 1; j < n; ++j)
|
540
|
+
{
|
541
|
+
double* t_line = M + i + j * n;
|
542
|
+
double head = *t_line;
|
543
|
+
for(int k = 1; k < n - i; ++k)
|
544
|
+
t_line[k] -= line_p[k] * head / current;
|
545
|
+
}
|
546
|
+
}
|
547
|
+
|
548
|
+
free(M);
|
549
|
+
return det;
|
550
|
+
}
|
551
|
+
|
552
|
+
void c_matrix_shift_identity(int n, double* A, int s_a)
|
553
|
+
{
|
554
|
+
for(int i = 0; i < n; ++i)
|
555
|
+
{
|
556
|
+
double* line_p = A + i * s_a;
|
557
|
+
for(int j = 0; j < n; ++j)
|
558
|
+
line_p[j] = (i == j) ? 1 : 0;
|
559
|
+
}
|
560
|
+
}
|
561
|
+
|
562
|
+
bool c_matrix_inverse(int n, const double* A, double* B)
|
563
|
+
{
|
564
|
+
int m = 2 * n;
|
565
|
+
double* M = malloc(m * n * sizeof(double));
|
566
|
+
strassen_copy(n, n, A, M, n, m);
|
567
|
+
c_matrix_shift_identity(n, M + n, m);
|
568
|
+
|
569
|
+
for(int i = 0; i < n; ++i)
|
570
|
+
{
|
571
|
+
double* line_p = M + i + i * m;
|
572
|
+
double current = *line_p;
|
573
|
+
|
574
|
+
if(current == 0)
|
575
|
+
for(int j = i + 1; j < n; ++j)
|
576
|
+
if(M[i + j * m] != 0)
|
577
|
+
{
|
578
|
+
double* buf = M + i + j * m;
|
579
|
+
swap_d_arrays(m - i, buf, line_p);
|
580
|
+
current = line_p[0];
|
581
|
+
}
|
582
|
+
|
583
|
+
if(current == 0)
|
584
|
+
{
|
585
|
+
free(M);
|
586
|
+
return false;
|
587
|
+
}
|
588
|
+
|
589
|
+
for(int j = 0; j < n; ++j)
|
590
|
+
{
|
591
|
+
double* t_line = M + i + j * m;
|
592
|
+
double head = *t_line;
|
593
|
+
if(i == j || head == 0)
|
594
|
+
continue;
|
595
|
+
for(int k = 1; k < m - i; ++k)
|
596
|
+
t_line[k] -= line_p[k] * head / current;
|
597
|
+
}
|
598
|
+
for(int k = 1; k < m - i; ++k)
|
599
|
+
line_p[k] = line_p[k] / current;
|
600
|
+
}
|
601
|
+
|
602
|
+
strassen_copy(n, n, M + n, B, m, n);
|
603
|
+
|
604
|
+
free(M);
|
605
|
+
return true;
|
606
|
+
}
|