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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31d4bbeb84c105ff8d28f067b375ff1b89120589baf84d5cff5a175db54f1522
4
- data.tar.gz: d8988e813b690465c0716b62b61cf36b71696381688bdcbcb008effd70235cc3
3
+ metadata.gz: b595a00ec07bf1d240037d16e3691d99f02b1313f0601ddc384c1bbc46378511
4
+ data.tar.gz: 0bc5cd22534b4add7364cc0531a438e5b909ab157c4778af1aaa3eb13e0afe9c
5
5
  SHA512:
6
- metadata.gz: d5d202092bbf94928f067f6c600db6075d5b2b7ff7a703a71a6811c667fe40b102611d676b185ebfc267dafb958ac547b1c6a1bcddecf3411306997cea050663
7
- data.tar.gz: e829008f0decdf7193fd96f561605496489fab34b0eb67d66ec9d6070c4fa1459a206d375ba529980842a30bc4ffd52b0b34b5eff55dff875dbc5885508170fd
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
 
@@ -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
- raise_check_range(m, 0, data->m);
92
- raise_check_range(n, 0, data->n);
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
  }
@@ -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
- raise_check_range(i, 0, data->n);
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, "==", vector_equal, 1);
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
@@ -30,4 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "rake", "~> 10.0"
31
31
  spec.add_development_dependency "rake-compiler"
32
32
  spec.add_development_dependency "minitest", "~> 5.0"
33
+ spec.add_development_dependency 'simplecov'
33
34
  end
data/lib/fast_matrix.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  require 'fast_matrix/version'
2
2
  require 'vector/vector'
3
3
  require 'matrix/matrix'
4
+ require 'scalar'
@@ -1,3 +1,3 @@
1
1
  module FastMatrix
2
- VERSION = "0.1.5"
2
+ VERSION = '0.1.6'
3
3
  end
@@ -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
- check_dimensions(row_count, column_count)
23
- matrix = self.new(row_count, column_count)
24
- matrix.each_with_index! { |_, i, j| block.call(i, j) } if block_given?
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 = Matrix.build(column.size, 1)
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 = Matrix.build(1, row.size)
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
- matrix = Matrix.build(values.size, values.size) { |i, j| i == j ? values[i] : 0 }
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
- Matrix.build(n, n) { |i, j| i == j ? value : 0 }
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 +n+ by +n+.
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(n)
132
- Matrix.build(n, n) { 0 }
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 Matrix.empty if matrices.empty?
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 = build(sizes[offset], sizes[1 + offset])
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
- # TODO: check class and use fast compare from C if possibly
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.5
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-28 00:00:00.000000000 Z
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