fast_matrix 0.1.5 → 0.1.6

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 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