fast_matrix 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +11 -0
- data/README.md +2 -0
- data/ext/fast_matrix/matrix.c +74 -3
- data/ext/fast_matrix/vector.c +6 -2
- data/fast_matrix.gemspec +1 -0
- data/lib/fast_matrix.rb +1 -0
- data/lib/fast_matrix/version.rb +1 -1
- data/lib/matrix/constructors.rb +31 -18
- data/lib/matrix/matrix.rb +1 -1
- data/lib/scalar.rb +58 -0
- data/lib/vector/vector.rb +30 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b595a00ec07bf1d240037d16e3691d99f02b1313f0601ddc384c1bbc46378511
|
4
|
+
data.tar.gz: 0bc5cd22534b4add7364cc0531a438e5b909ab157c4778af1aaa3eb13e0afe9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1eebf62db5b0214d6a04414cff95b6179bcfea2fc972397da325bb8a4efd871768711a9989572d18f7eb6ca1f51da7b0de84d3c1aa56547703ed4e0d72c4958b
|
7
|
+
data.tar.gz: 823754bfaf70c9ec3b1dafe6ba409ec954e332a7d48f66ef8e9327bbddcd9288a8d4dc55f053c990279f1ad17455384d92a68bd7b214e074dbd9f295b98f3019
|
data/.travis.yml
CHANGED
@@ -2,7 +2,18 @@ language: ruby
|
|
2
2
|
cache: bundler
|
3
3
|
rvm:
|
4
4
|
- 2.6.5
|
5
|
+
env:
|
6
|
+
global:
|
7
|
+
- CC_TEST_REPORTER_ID=$TEST_ID
|
5
8
|
before_install: gem install bundler -v 2.0.2
|
9
|
+
before_script:
|
10
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
11
|
+
- chmod +x ./cc-test-reporter
|
12
|
+
- ./cc-test-reporter before-build
|
13
|
+
script:
|
14
|
+
- bundle exec rake
|
15
|
+
after_script:
|
16
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
6
17
|
deploy:
|
7
18
|
provider: rubygems
|
8
19
|
api_key: $API_KEY
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
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)
|
2
4
|
|
3
5
|
# FastMatrix
|
4
6
|
|
data/ext/fast_matrix/matrix.c
CHANGED
@@ -71,6 +71,9 @@ VALUE matrix_set(VALUE self, VALUE row, VALUE column, VALUE v)
|
|
71
71
|
|
72
72
|
struct matrix* data;
|
73
73
|
TypedData_Get_Struct(self, struct matrix, &matrix_type, data);
|
74
|
+
|
75
|
+
m = (m < 0) ? data->m + m : m;
|
76
|
+
n = (n < 0) ? data->n + n : n;
|
74
77
|
|
75
78
|
raise_check_range(m, 0, data->m);
|
76
79
|
raise_check_range(n, 0, data->n);
|
@@ -87,9 +90,12 @@ VALUE matrix_get(VALUE self, VALUE row, VALUE column)
|
|
87
90
|
|
88
91
|
struct matrix* data;
|
89
92
|
TypedData_Get_Struct(self, struct matrix, &matrix_type, data);
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
+
|
94
|
+
m = (m < 0) ? data->m + m : m;
|
95
|
+
n = (n < 0) ? data->n + n : n;
|
96
|
+
|
97
|
+
if(m < 0 || n < 0 || n >= data->n || m >= data->m)
|
98
|
+
return Qnil;
|
93
99
|
|
94
100
|
return DBL2NUM(data->data[m + data->m * n]);
|
95
101
|
}
|
@@ -517,6 +523,51 @@ VALUE matrix_sub_with(VALUE self, VALUE value)
|
|
517
523
|
return result;
|
518
524
|
}
|
519
525
|
|
526
|
+
double determinant(int n, const double* A)
|
527
|
+
{
|
528
|
+
double* M = malloc(n * n * sizeof(double));
|
529
|
+
double det = 1;
|
530
|
+
copy_d_array(n * n, A, M);
|
531
|
+
|
532
|
+
for(int i = 0; i < n; ++i)
|
533
|
+
{
|
534
|
+
const double* line_p = M + i + i * n;
|
535
|
+
double current = *line_p;
|
536
|
+
det *= current;
|
537
|
+
|
538
|
+
if(current == 0)
|
539
|
+
{
|
540
|
+
free(M);
|
541
|
+
return 0;
|
542
|
+
}
|
543
|
+
|
544
|
+
for(int j = i + 1; j < n; ++j)
|
545
|
+
{
|
546
|
+
double* t_line = M + i + j * n;
|
547
|
+
double head = *t_line;
|
548
|
+
for(int k = 1; k < n - i; ++k)
|
549
|
+
t_line[k] -= line_p[k] * head / current;
|
550
|
+
}
|
551
|
+
}
|
552
|
+
|
553
|
+
free(M);
|
554
|
+
return det;
|
555
|
+
}
|
556
|
+
|
557
|
+
VALUE matrix_determinant(VALUE self)
|
558
|
+
{
|
559
|
+
struct matrix* A;
|
560
|
+
TypedData_Get_Struct(self, struct matrix, &matrix_type, A);
|
561
|
+
|
562
|
+
|
563
|
+
int m = A->m;
|
564
|
+
int n = A->n;
|
565
|
+
if(m != n)
|
566
|
+
rb_raise(fm_eIndexError, "Not a square matrix");
|
567
|
+
|
568
|
+
return DBL2NUM(determinant(n, A->data));
|
569
|
+
}
|
570
|
+
|
520
571
|
VALUE matrix_sub_from(VALUE self, VALUE value)
|
521
572
|
{
|
522
573
|
struct matrix* A;
|
@@ -546,6 +597,24 @@ VALUE matrix_fill(VALUE self, VALUE value)
|
|
546
597
|
return self;
|
547
598
|
}
|
548
599
|
|
600
|
+
VALUE matrix_equal(VALUE self, VALUE value)
|
601
|
+
{
|
602
|
+
struct matrix* A;
|
603
|
+
struct matrix* B;
|
604
|
+
TypedData_Get_Struct(self, struct matrix, &matrix_type, A);
|
605
|
+
TypedData_Get_Struct(value, struct matrix, &matrix_type, B);
|
606
|
+
|
607
|
+
if(A->n != B->n || A->m != B->m)
|
608
|
+
return Qfalse;
|
609
|
+
|
610
|
+
int n = A->n;
|
611
|
+
int m = B->m;
|
612
|
+
|
613
|
+
if(equal_d_arrays(n * m, A->data, B->data))
|
614
|
+
return Qtrue;
|
615
|
+
return Qfalse;
|
616
|
+
}
|
617
|
+
|
549
618
|
VALUE matrix_abs(VALUE self)
|
550
619
|
{
|
551
620
|
struct matrix* A;
|
@@ -604,4 +673,6 @@ void init_fm_matrix()
|
|
604
673
|
rb_define_method(cMatrix, "strassen", strassen, 1);
|
605
674
|
rb_define_method(cMatrix, "abs", matrix_abs, 0);
|
606
675
|
rb_define_method(cMatrix, ">=", matrix_greater_or_equal, 1);
|
676
|
+
rb_define_method(cMatrix, "determinant", matrix_determinant, 0);
|
677
|
+
rb_define_method(cMatrix, "eql?", matrix_equal, 1);
|
607
678
|
}
|
data/ext/fast_matrix/vector.c
CHANGED
@@ -69,6 +69,7 @@ VALUE vector_set(VALUE self, VALUE idx, VALUE v)
|
|
69
69
|
struct vector* data;
|
70
70
|
TypedData_Get_Struct(self, struct vector, &vector_type, data);
|
71
71
|
|
72
|
+
i = (i < 0) ? data->n + i : i;
|
72
73
|
raise_check_range(i, 0, data->n);
|
73
74
|
|
74
75
|
data->data[i] = x;
|
@@ -83,7 +84,10 @@ VALUE vector_get(VALUE self, VALUE idx)
|
|
83
84
|
struct vector* data;
|
84
85
|
TypedData_Get_Struct(self, struct vector, &vector_type, data);
|
85
86
|
|
86
|
-
|
87
|
+
i = (i < 0) ? data->n + i : i;
|
88
|
+
|
89
|
+
if(i < 0 || i >= data->n)
|
90
|
+
return Qnil;
|
87
91
|
|
88
92
|
return DBL2NUM(data->data[i]);
|
89
93
|
}
|
@@ -267,7 +271,7 @@ void init_fm_vector()
|
|
267
271
|
rb_define_method(cVector, "size", c_vector_size, 0);
|
268
272
|
rb_define_method(cVector, "+", vector_add_with, 1);
|
269
273
|
rb_define_method(cVector, "+=", vector_add_from, 1);
|
270
|
-
rb_define_method(cVector, "
|
274
|
+
rb_define_method(cVector, "eql?", vector_equal, 1);
|
271
275
|
rb_define_method(cVector, "clone", vector_copy, 0);
|
272
276
|
rb_define_method(cVector, "*", vector_multiply, 1);
|
273
277
|
}
|
data/fast_matrix.gemspec
CHANGED
data/lib/fast_matrix.rb
CHANGED
data/lib/fast_matrix/version.rb
CHANGED
data/lib/matrix/constructors.rb
CHANGED
@@ -6,7 +6,6 @@ module FastMatrix
|
|
6
6
|
# Constructors as in the standard matrix
|
7
7
|
#
|
8
8
|
class Matrix
|
9
|
-
|
10
9
|
#
|
11
10
|
# Creates a matrix of size +row_count+ x +column_count+.
|
12
11
|
# It fills the values by calling the given block,
|
@@ -19,10 +18,10 @@ module FastMatrix
|
|
19
18
|
# => a 3x3 matrix with random elements
|
20
19
|
#
|
21
20
|
def self.build(row_count, column_count = row_count, &block)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
matrix
|
21
|
+
matrix = create_with_check(row_count, column_count)
|
22
|
+
raise NotImplementedError, 'Issue#17' unless block_given?
|
23
|
+
|
24
|
+
matrix.each_with_index! { |_, i, j| block.call(i, j) }
|
26
25
|
end
|
27
26
|
|
28
27
|
#
|
@@ -68,7 +67,7 @@ module FastMatrix
|
|
68
67
|
# 6
|
69
68
|
#
|
70
69
|
def self.column_vector(column)
|
71
|
-
matrix =
|
70
|
+
matrix = create_with_check(column.size, 1)
|
72
71
|
column.each_with_index { |elem, i| matrix[i, 0] = elem }
|
73
72
|
matrix
|
74
73
|
end
|
@@ -80,7 +79,7 @@ module FastMatrix
|
|
80
79
|
# => 4 5 6
|
81
80
|
#
|
82
81
|
def self.row_vector(row)
|
83
|
-
matrix =
|
82
|
+
matrix = create_with_check(1, row.size)
|
84
83
|
row.each_with_index { |elem, j| matrix[0, j] = elem }
|
85
84
|
matrix
|
86
85
|
end
|
@@ -93,8 +92,7 @@ module FastMatrix
|
|
93
92
|
# 0 0 -3
|
94
93
|
#
|
95
94
|
def self.diagonal(*values)
|
96
|
-
|
97
|
-
matrix
|
95
|
+
build(values.size, values.size) { |i, j| i == j ? values[i] : 0 }
|
98
96
|
end
|
99
97
|
|
100
98
|
#
|
@@ -105,7 +103,7 @@ module FastMatrix
|
|
105
103
|
# 0 5
|
106
104
|
#
|
107
105
|
def self.scalar(n, value)
|
108
|
-
|
106
|
+
build(n, n) { |i, j| i == j ? value : 0 }
|
109
107
|
end
|
110
108
|
|
111
109
|
#
|
@@ -122,14 +120,24 @@ module FastMatrix
|
|
122
120
|
alias I identity
|
123
121
|
end
|
124
122
|
|
123
|
+
##
|
124
|
+
# Creates a filled matrix
|
125
|
+
# Matrix.fill(42, 2, 4)
|
126
|
+
# => 42 42 42 42
|
127
|
+
# 42 42 42 42
|
128
|
+
##
|
129
|
+
def self.fill(value, row_count, column_count = row_count)
|
130
|
+
create_with_check(row_count, column_count).fill!(value)
|
131
|
+
end
|
132
|
+
|
125
133
|
#
|
126
|
-
# Creates a zero matrix +
|
127
|
-
# Matrix.zero(2)
|
128
|
-
# => 0 0
|
129
|
-
# 0 0
|
134
|
+
# Creates a zero matrix +row_count+ by +column_count+.
|
135
|
+
# Matrix.zero(2, 3)
|
136
|
+
# => 0 0 0
|
137
|
+
# 0 0 0
|
130
138
|
#
|
131
|
-
def self.zero(
|
132
|
-
|
139
|
+
def self.zero(row_count, column_count = row_count)
|
140
|
+
fill(0, row_count, column_count)
|
133
141
|
end
|
134
142
|
|
135
143
|
#
|
@@ -199,7 +207,7 @@ module FastMatrix
|
|
199
207
|
# Matrix.combine(x, y) {|a, b| a - b} # => Matrix[[5, 4], [1, 0]]
|
200
208
|
# TODO: optimize in C
|
201
209
|
def self.combine(*matrices)
|
202
|
-
return
|
210
|
+
return empty if matrices.empty?
|
203
211
|
|
204
212
|
result = convert(matrices.first)
|
205
213
|
matrices[1..matrices.size].each do |m|
|
@@ -214,6 +222,11 @@ module FastMatrix
|
|
214
222
|
class << Matrix
|
215
223
|
private
|
216
224
|
|
225
|
+
def create_with_check(row_count, column_count)
|
226
|
+
check_dimensions(row_count, column_count)
|
227
|
+
new(row_count, column_count)
|
228
|
+
end
|
229
|
+
|
217
230
|
def check_empty_matrix(row_count, column_count)
|
218
231
|
empty if row_count.zero? || column_count.zero?
|
219
232
|
end
|
@@ -237,7 +250,7 @@ module FastMatrix
|
|
237
250
|
def lines(lines, main_is_rows)
|
238
251
|
sizes = [lines.size, (lines[0] || []).size]
|
239
252
|
offset = main_is_rows ? 0 : -1
|
240
|
-
matrix =
|
253
|
+
matrix = create_with_check(sizes[offset], sizes[1 + offset])
|
241
254
|
lines.each_with_index do |second_dim, main_index|
|
242
255
|
raise IndexError if second_dim.size != sizes[1]
|
243
256
|
|
data/lib/matrix/matrix.rb
CHANGED
@@ -66,7 +66,7 @@ module FastMatrix
|
|
66
66
|
|
67
67
|
# FIXME: for compare with standard matrix
|
68
68
|
def ==(other)
|
69
|
-
|
69
|
+
return eql?(other) if other.class == Matrix
|
70
70
|
return false unless %i[row_size column_size \[\]].all? { |x| other.respond_to? x }
|
71
71
|
return false unless self.row_size == other.row_size && self.column_size == other.column_size
|
72
72
|
|
data/lib/scalar.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'fast_matrix/fast_matrix'
|
2
|
+
|
3
|
+
module FastMatrix
|
4
|
+
|
5
|
+
class Matrix
|
6
|
+
#
|
7
|
+
# The coerce method provides support for Ruby type coercion.
|
8
|
+
# This coercion mechanism is used by Ruby to handle mixed-type
|
9
|
+
# numeric operations: it is intended to find a compatible common
|
10
|
+
# type between the two operands of the operator.
|
11
|
+
# See also Numeric#coerce.
|
12
|
+
#
|
13
|
+
def coerce(other)
|
14
|
+
case other
|
15
|
+
when Numeric
|
16
|
+
return Scalar.new(other), self
|
17
|
+
else
|
18
|
+
raise TypeError, "#{self.class} can't be coerced into #{other.class}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Vector
|
24
|
+
#
|
25
|
+
# The coerce method provides support for Ruby type coercion.
|
26
|
+
# This coercion mechanism is used by Ruby to handle mixed-type
|
27
|
+
# numeric operations: it is intended to find a compatible common
|
28
|
+
# type between the two operands of the operator.
|
29
|
+
# See also Numeric#coerce.
|
30
|
+
#
|
31
|
+
def coerce(other)
|
32
|
+
case other
|
33
|
+
when Numeric
|
34
|
+
return Scalar.new(other), self
|
35
|
+
else
|
36
|
+
raise TypeError, "#{self.class} can't be coerced into #{other.class}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
class Scalar < Numeric # :nodoc:
|
44
|
+
|
45
|
+
def initialize(value)
|
46
|
+
@value = value
|
47
|
+
end
|
48
|
+
|
49
|
+
def *(other)
|
50
|
+
case other
|
51
|
+
when Vector, Matrix
|
52
|
+
other * @value
|
53
|
+
else
|
54
|
+
Scalar.new(@value * other)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/vector/vector.rb
CHANGED
@@ -3,6 +3,24 @@ require 'vector/constructors'
|
|
3
3
|
module FastMatrix
|
4
4
|
class Vector
|
5
5
|
|
6
|
+
#
|
7
|
+
# Create fast vector from standard vector
|
8
|
+
#
|
9
|
+
def self.convert(vector)
|
10
|
+
elements(vector)
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Convert to standard ruby vector.
|
15
|
+
#
|
16
|
+
def convert
|
17
|
+
::Vector.elements(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_ary
|
21
|
+
Array.new(size) { |i| self[i] }
|
22
|
+
end
|
23
|
+
|
6
24
|
def each_with_index
|
7
25
|
(0...size).each do |i|
|
8
26
|
yield self[i], i
|
@@ -16,5 +34,17 @@ module FastMatrix
|
|
16
34
|
self
|
17
35
|
end
|
18
36
|
|
37
|
+
# FIXME: for compare with standard vector
|
38
|
+
def ==(other)
|
39
|
+
return eql?(other) if other.class == Vector
|
40
|
+
return false unless %i[size \[\]].all? { |x| other.respond_to? x }
|
41
|
+
return false unless self.size == other.size
|
42
|
+
|
43
|
+
result = true
|
44
|
+
each_with_index do |elem, i|
|
45
|
+
result &&= elem == other[i].to_f
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
19
49
|
end
|
20
50
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_matrix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mmcs_ruby
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-10-
|
11
|
+
date: 2019-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
description: Ruby wrapper around C matrices implementation
|
70
84
|
email:
|
71
85
|
- poganesyan@sfedu.ru
|
@@ -100,6 +114,7 @@ files:
|
|
100
114
|
- lib/fast_matrix/version.rb
|
101
115
|
- lib/matrix/constructors.rb
|
102
116
|
- lib/matrix/matrix.rb
|
117
|
+
- lib/scalar.rb
|
103
118
|
- lib/vector/constructors.rb
|
104
119
|
- lib/vector/vector.rb
|
105
120
|
homepage: https://github.com/mmcs-ruby/fast_matrix
|