Class: Mat

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/kmat.rb,
lib/kmat/misc.rb,
lib/kmat/arith.rb,
lib/kmat/linalg.rb,
lib/kmat/random.rb,
lib/kmat/logical.rb,
lib/kmat/version.rb,
lib/kmat/accessor.rb,
lib/kmat/statistics.rb

Defined Under Namespace

Modules: MatrixProductOperator Classes: InternalError, MismatchedDimensionError, NotImplementedYetError, SharingError, UncomputableMatrixError, ValueTypeError

Constant Summary collapse

VERSION =
"0.1.0"

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Enumerable

#argsort, #argsort_by

Class Method Details

.blocks(args) ⇒ Object

for example, Mat.blocks([a, b], [c, d]) returns a single matrix of [a, b; c, d]



121
122
123
124
125
# File 'lib/kmat/accessor.rb', line 121

def blocks(args)
  vstack(*(args.map do |row|
    hstack(*row)
  end))
end

.hilb(n, type = :float) ⇒ Object



2
3
4
5
6
# File 'lib/kmat/misc.rb', line 2

def hilb(n, type=:float)
  self.new(n, n, type) do |i, j|
    1.quo(i+j+1)
  end
end

.hstack(*mats) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/kmat/accessor.rb', line 146

def hstack(*mats)
  m, n = mats[0].shape
  1.upto(mats.size-1) do |i|
    mat = mats[i]
    raise MismatchedDimensionError, 'row-sizes must be the same' if mat.row_size != m
    n += mat.col_size
  end
  ret = Mat.new(m, n, mats[0].vtype)
  k = 0
  m = Mat.irange(m)
  mats.each do |mat|
    ret[m, Mat.new(mat.col_size, 1, :int) do |i, j|
      i+k
    end] = mat
    k += mat.col_size
  end
  ret
end

.load(file) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/kmat/misc.rb', line 7

def load(file)
  case file
  when String
    ret = nil
    File.open(file) do |f|
      ret = Marshal.load(f)
    end
    ret
  when IO
    Marshal.load(file)
  else
    raise ArgumentError, 'the argument must be a filepath or an IO object'
  end
end

.max(*args) ⇒ Object Also known as: maximum



159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/kmat/arith.rb', line 159

def max(*args)
  case args.size
  when 0
    nil
  when 1
    args[0]
  else
    ret = args[0].dup
    1.upto(args.size-1) { |i|
      ret.maximum!(args[i])
    }
    ret
  end
end

.min(*args) ⇒ Object Also known as: minimum



174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/kmat/arith.rb', line 174

def min(*args)
  case args.size
  when 0
    nil
  when 1
    args[0]
  else
    ret = args[0].dup
    1.upto(args.size-1) { |i|
      ret.minimum!(args[i])
    }
    ret
  end
end

.rand(m = 1, n = 1, random: $MatRandom) ⇒ Object



100
101
102
# File 'lib/kmat/random.rb', line 100

def rand(m=1, n=1, random: $MatRandom)
  _rand0(m, n, random)
end

.rand_orth(n, random: $MatRandom) ⇒ Object



69
70
71
# File 'lib/kmat/linalg.rb', line 69

def self.rand_orth(n, random: $MatRandom)
  Mat.new(n, n, :float).rand_orth(random: random)
end

.randn(m = 1, n = 1, random: $MatRandom) ⇒ Object



103
104
105
# File 'lib/kmat/random.rb', line 103

def randn(m=1, n=1, random: $MatRandom)
  _randn0(m, n, random)
end

.vstack(*mats) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/kmat/accessor.rb', line 127

def vstack(*mats)
  m, n = mats[0].shape
  1.upto(mats.size-1) do |i|
    mat = mats[i]
    raise MismatchedDimensionError, 'column-sizes must be the same' if mat.col_size != n
    m += mat.row_size
  end
  ret = Mat.new(m, n, mats[0].vtype)
  k = 0;
  n = Mat.irange(n)
  mats.each do |mat|
    ret[Mat.new(mat.row_size, 1, :int) do |i, j|
      i+k
    end, n] = mat
    k += mat.row_size
  end
  ret
end

Instance Method Details

#*(other) ⇒ Object



59
60
61
62
63
64
65
# File 'lib/kmat/arith.rb', line 59

def *(other)
  if other.kind_of?(Mat)
    raise ArgumentError, "Mat#* is available only for scalar multiplication. To use Mat#*(Mat) for matrix product, call `using Mat::MatrixProductOperator'"
  else
    self.dup.s_mul!(other)
  end
end

#**(other) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/kmat/arith.rb', line 111

def **(other)
  case other
  when Integer
    ret, temp = self.dup, self.dup
    ret.eye
    if 0 <= other
      a = self.dup
    else
      a = self.inv
      other = -other
    end
    loop do
      if other % 2 == 1
        temp.mprod!(ret, a)
        temp, ret = ret, temp
      end
      other = other.div(2)
      break if other == 0
      temp.mprod!(a, a)
      temp, a = a, temp
    end
    ret
  when Float
    if self.symmetry?
      v, d = self.symmetrize.sym_evd
      d.diag.s_pow!(other)
      foo = v.mprod(d)
      d.mprod!(foo, v.t!)
    else
      raise UncomputableMatrixError, "cannot compute float power of non-symmetric matrcies"
    end
  when Rational
    self ** other.to_f
  else
    raise ArgumentError, "Mat powered by #{other.class} is not supported"
  end
end

#/(other) ⇒ Object



70
71
72
73
74
75
76
# File 'lib/kmat/arith.rb', line 70

def /(other)
  if other.kind_of?(Mat)
    raise ArgumentError, "Mat#/ is available only for scalar multiplication with reciprocal. To use Mat#/(Mat) as an alias of Mat#over, call `using Mat::MatrixProductOperator`"
  else
    self.dup.s_div!(other)
  end
end

#<(other) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/kmat/logical.rb', line 59

def <(other)
  return false if self.equal?(other)
  unless other.kind_of?(Mat)
    raise ArgumentError, "Mat < #{other.class} is not defined"
  end
  if self.vtype != other.vtype
    raise ValueTypeError, "value types must be the same"
  elsif self.size != other.size
    raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
  end
  each_with_index do |e, i, j|
    return false unless e < other[i, j]
  end
  true
end

#<=(other) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/kmat/logical.rb', line 74

def <=(other)
  return false if self.equal?(other)
  unless other.kind_of?(Mat)
    raise ArgumentError, "Mat <= #{other.class} is not defined"
  end
  if self.vtype != other.vtype
    raise ValueTypeError, "value types must be the same"
  elsif self.size != other.size
    raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
  end
  each_with_index do |e, i, j|
    return false unless e <= other[i, j]
  end
  true
end

#==(other) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/kmat/logical.rb', line 47

def ==(other)
  return true if self.equal?(other)
  return false unless other.kind_of?(Mat)
  if self.vtype == other.vtype && self.size == other.size
    each_with_index do |e, i, j|
      return false unless e == other[i, j]
    end
    true
  else
    false
  end
end

#===(other) ⇒ Object



2
3
4
5
6
7
8
# File 'lib/kmat/accessor.rb', line 2

def ===(other)
  if other.kind_of?(Mat)
    self == other
  else
    false
  end
end

#>(other) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/kmat/logical.rb', line 89

def >(other)
  return false if self.equal?(other)
  unless other.kind_of?(Mat)
    raise ArgumentError, "Mat > #{other.class} is not defined"
  end
  if self.vtype != other.vtype
    raise ValueTypeError, "value types must be the same"
  elsif self.size != other.size
    raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
  end
  each_with_index do |e, i, j|
    return false unless e > other[i, j]
  end
  true
end

#>=(other) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/kmat/logical.rb', line 104

def >=(other)
  return false if self.equal?(other)
  unless other.kind_of?(Mat)
    raise ArgumentError, "Mat > #{other.class} is not defined"
  end
  if self.vtype != other.vtype
    raise ValueTypeError, "value types must be the same"
  elsif self.size != other.size
    raise MismatchedDimensionError, "the sizes must be the same, (#{self.size.join(', ')}) != (#{other.size.join(', ')})"
  end
  each_with_index do |e, i, j|
    return false unless e >= other[i, j]
  end
  true
end

#[](*idx) ⇒ Object



10
11
12
13
14
15
16
17
18
19
# File 'lib/kmat/accessor.rb', line 10

def [](*idx)
  if block_given?
    tmp = self.bracket(*idx)
    ret = yield(tmp)
    tmp.__send__(:_kill)
    ret
  else
    self.bracket(*idx)
  end
end

#add(other) ⇒ Object Also known as: +



11
12
13
14
15
16
17
# File 'lib/kmat/arith.rb', line 11

def add(other)
  if other.kind_of?(Mat)
    self.dup.add!(broadcast(other))
  else
    self.dup.s_add!(other)
  end
end

#add_times(other, alpha) ⇒ Object



78
79
80
81
82
83
84
# File 'lib/kmat/arith.rb', line 78

def add_times(other, alpha)
  if other.kind_of?(Mat)
    self.dup.add_times!(broadcast(other), alpha)
  else
    self.dup.s_mul!(other*alpha)
  end
end

#all?(*args) ⇒ Boolean

Returns:

  • (Boolean)


2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/kmat/logical.rb', line 2

def all?(*args)
  if block_given?
    each do |ent|
      return false unless yield(ent, *args)
    end
  elsif args.size == 0
    if self.vtype == :bool
      each do |ent|
        return false unless ent
      end
    else
      return enum_for(__method__)
    end
  else
    each do |ent|
      args.each do |arg|
        return false unless arg === ent
      end
    end
  end
  return true
end

#any?(*args) ⇒ Boolean

Returns:

  • (Boolean)


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/kmat/logical.rb', line 24

def any?(*args)
  if block_given?
    each do |ent|
      return true if yield(ent, *args)
    end
  elsif args.size == 0
    if self.vtype == :bool
      each do |ent|
        return true if ent
      end
    else
      return enum_for(__method__)
    end
  else
    each do |ent|
      args.each do |arg|
        return true if arg === ent
      end
    end
  end
  return false
end

#broadcast(other, vt = nil) ⇒ Object

extend ‘other’ to fit the shape of self this is similar to Python’s numpy broadcasting



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/kmat/accessor.rb', line 42

def broadcast(other, vt=nil)
  if other.kind_of?(Mat)
    if other.row_size == 1
      if other.col_size == 1
        other.repmat(row_size(), col_size())
      elsif other.col_size == self.col_size
        other.repmat(self.row_size, 1)
      else
        raise MismatchedDimensionError, "can't broadcast from (#{other.size.join(', ')}) to (#{self.size.join(', ')})"
      end
    elsif other.row_size == self.row_size
      if other.col_size == 1
        other.repmat(1, col_size())
      elsif other.col_size == self.col_size
        other
      else
        raise MismatchedDimensionError, "can't broadcast from (#{self.size.join(', ')}) to (#{other.size.join(', ')})"
      end
    else
      raise MismatchedDimensionError, "can't broadcast from (#{self.size.join(', ')}) to (#{other.size.join(', ')})"
    end
  else
    vt = vtype() if vt.nil?
    Mat.new(row_size(), col_size(), vt).fill(other)
  end
end

#coerce(other) ⇒ Object

to define Numeric * Mat as Mat#scalar(Numeric) remaining Mat * Mat is undefined, this returns non‐standard value



4
5
6
7
8
9
10
# File 'lib/kmat/arith.rb', line 4

def coerce(other)
  if caller.first[/`([^']*)'/, 1] == '*'
    [self, other]
  else
    raise TypeError, "Mat can't be coerced into #{other.class}"
  end
end

#diag(k = 0) ⇒ Object



114
115
116
# File 'lib/kmat/accessor.rb', line 114

def diag(k=0)
  _diag_ul(k)
end

#distance(other) ⇒ Object

distance (Frobenius norm of the difference)



229
230
231
# File 'lib/kmat/linalg.rb', line 229

def distance(other)
  self.dup.sub!(other).normf
end

#e_div(other) ⇒ Object



34
35
36
37
38
39
40
# File 'lib/kmat/arith.rb', line 34

def e_div(other)
  if other.kind_of?(Mat)
    self.dup.e_div!(broadcast(other))
  else
    self.dup.s_div!(other)
  end
end

#e_mul(other) ⇒ Object



27
28
29
30
31
32
33
# File 'lib/kmat/arith.rb', line 27

def e_mul(other)
  if other.kind_of?(Mat)
    self.dup.e_mul!(broadcast(other))
  else
    self.dup.s_mul!(other)
  end
end

#eigen_valuesObject



130
131
132
133
134
135
136
# File 'lib/kmat/linalg.rb', line 130

def eigen_values
  if symmetry?
    symmetrize().sym_eigen_values()
  else
    ge_eigen_values()
  end
end

#eq(other) ⇒ Object



120
121
122
123
124
125
# File 'lib/kmat/logical.rb', line 120

def eq(other)
  unless other.kind_of?(Mat) && other.size == self.size
    other = broadcast(other)
  end
  Mat.new(row_size(), col_size(), :bool).eq!(self, other)
end

#evdObject



137
138
139
140
141
142
143
# File 'lib/kmat/linalg.rb', line 137

def evd
  if symmetry?
    symmetrize().sym_evd()
  else
    ge_evd()
  end
end

#flip(dim = :both) ⇒ Object

flip row, column or both axis ‘dim’ Symbol specifies fliping axis (:row, :col, :both, :none are available)



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/kmat/accessor.rb', line 85

def flip(dim=:both)
  dim = dim.to_sym if dim.respond_to?(:to_sym)
  m, n = *shape()
  case dim
  when :both, :b
    ri = Mat.new(m, 1, :int) do |i, j|
      m-i-1
    end
    ci = Mat.new(n, 1, :int) do |i, j|
      n-i-1
    end
    self[ri, ci]
  when :row, :r
    ri = Mat.new(m, 1, :int) do |i, j|
      m-i-1
    end
    self[ri, nil]
  when :col, :c
    ci = Mat.new(n, 1, :int) do |i, j|
      n-i-1
    end
    self[nil, ci]
  when :none, :n
    self[]
  else
    raise ArgumentError, "unknown axis symbol #{dim.inspect}"
  end
end

#ge(other) ⇒ Object



144
145
146
147
148
149
# File 'lib/kmat/logical.rb', line 144

def ge(other)
  unless other.kind_of?(Mat) && other.size == self.size
    other = broadcast(other)
  end
  Mat.new(row_size(), col_size(), :bool).ge!(self, other)
end

#geo_mean(arg = :all) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/kmat/statistics.rb', line 87

def geo_mean(arg=:all)
  foo = self.log.mean(arg)
  if foo.kind_of?(Mat)
    foo.exp!
  elsif arg.kind_of?(Mat)
    arg.exp!
    arg[0, 0]
  else
    Math.exp(foo)
  end
end

#geo_normalize(arg = :all) ⇒ Object



48
49
50
# File 'lib/kmat/misc.rb', line 48

def geo_normalize(arg=:all)
  self.dup.geo_normalize!(arg)
end

#geo_normalize!(arg = :all) ⇒ Object



38
39
40
41
42
43
44
45
46
47
# File 'lib/kmat/misc.rb', line 38

def geo_normalize!(arg=:all)
  self.log!
  foo = self.mean(arg)
  if foo.kind_of?(Mat)
    self.sub!(self.broadcast(foo))
  else
    self.s_sub!(foo)
  end
  self.exp!
end

#gt(other) ⇒ Object



138
139
140
141
142
143
# File 'lib/kmat/logical.rb', line 138

def gt(other)
  unless other.kind_of?(Mat) && other.size == self.size
    other = broadcast(other)
  end
  Mat.new(row_size(), col_size(), :bool).gt!(self, other)
end

#hypot(other) ⇒ Object



149
150
151
152
153
154
155
# File 'lib/kmat/arith.rb', line 149

def hypot(other)
  if other.kind_of?(Mat)
    self.dup.hypot!(broadcast(other))
  else
    self.dup.s_hypot!(other)
  end
end

#iprod(*args, inverse: false) ⇒ Object Also known as: inner_product

inner product let x and y are column vectors and M is a square matrix the following is available (1) x.iprod => x’*x (2) x.iprod(y) => x’*y (3) M.iprod(x) => x’*M*x (4) M.iprod(x, y) => x’*M*y if ‘inverse’ is true, M is replaced by its Moore–Penrose inverse in case (1) or (2), ‘inverse’ is ignored if x or y is row vector, take transpose automatically



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/kmat/linalg.rb', line 155

def iprod(*args, inverse: false)
  case  args.size
  when 0
    if vector? # case 1
      _iprod(self)
    else
      raise MismatchedDimensionError, "self must be a vector"
    end
  when 1
    o = args[0]
    if o.vector?
      if vector? # case 2
        _iprod(o)
      else # case 3
        if !square?
          raise MismatchecDimensionError, "M must be square for M.iprod(x)"
        elsif inverse
          temp = Mat.new(row_size, 1, vtype)
          if o.col_size == 1
            begin
              temp.solve!(self, o)
            rescue UncomputableMatrixError
              temp.ls!(self, o)
            end
          else
            begin
              temp.tsolve!(self, o)
            rescue UncomputableMatrixError
              temp.tls!(self, o)
            end
          end
        else
          temp = Mat.new(row_size, 1, vtype)
          if o.col_size == 1
            temp.mprod!(self, o)
          else
            temp.mprod!(o, self)
          end
        end
        temp.__send__(:_iprod, o)
      end
    else
      raise MismatchedDimensionError, "as iprod with single argument, x.iprod(y) and M.iprod(x) are available, not x.iprod(M) or others"
    end
  when 2 # case 4
    x, y = *args
    if !square? || !x.vector? || !y.vector? || x.length != row_size || y.length != row_size
      raise MismatchecDimensionError, "as iprod with 2 arguments, only M.iprod(x, y) is available, not others"
    end
    temp = Mat(row_size, 1, vtype)
    if y.col_size == 1
      temp.mprod!(y)
    else
      if y.frozen?
        y = y.dup
        y.transpose
        temp.mprod!(y)
      else
        begin
          y.transpose
          temp.mprod!(y)
        ensure
          y.transpose
        end
      end
    end
    x.__send__(:_iprod, temp)
  else
    raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..2)"
  end
end

#le(other) ⇒ Object



132
133
134
135
136
137
# File 'lib/kmat/logical.rb', line 132

def le(other)
  unless other.kind_of?(Mat) && other.size == self.size
    other = broadcast(other)
  end
  Mat.new(row_size(), col_size(), :bool).le!(self, other)
end

#least_squares(b, tor: nil, weight: nil, transpose: false) ⇒ Object Also known as: ls



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/kmat/linalg.rb', line 18

def least_squares(b, tor: nil, weight: nil, transpose: false)
  if tor
    raise ArgumentError, "tor and weight must not specify at once" if weight
    raise ArgumentError, "for conjugate LS, auto-transpose is not available" if transpose
    ls_conj(b, tor)
  elsif weight
    raise ArgumentError, "for weighted LS, auto-transpose is not available" if transpose
    wls(b, weight)
  else
    if transpose
      tls(b)
    else
      Mat.new(*b.shape, :float).__send__(:_ls, self, b)
    end
  end
end

#least_squares!(a, b, tor: nil, weight: nil, transpose: false) ⇒ Object Also known as: ls!



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/kmat/linalg.rb', line 2

def least_squares!(a, b, tor: nil, weight: nil, transpose: false)
  if tor
    raise ArgumentError, "tor and weight must not specify at once" if weight
    raise ArgumentError, "for conjugate LS, auto-transpose is not available" if transpose
    _ls_conj(a, b, tor)
  elsif weight
    raise ArgumentError, "for weighted LS, auto-transpose is not available" if transpose
    wls!(a, b, weight)
  else
    if transpose
      tls!(a, b)
    else
      _ls(a, b)
    end
  end
end

#ls_conj(b, tor: Float::EPSILON) ⇒ Object



40
41
42
# File 'lib/kmat/linalg.rb', line 40

def ls_conj(b, tor: Float::EPSILON)
  Mat.new(self.col_size, 1, :float).ls_conj!(self, b, tor: tor)
end

#ls_conj!(a, b, tor: Float::EPSILON) ⇒ Object



37
38
39
# File 'lib/kmat/linalg.rb', line 37

def ls_conj!(a, b, tor: Float::EPSILON)
  _ls_conj(a, b, tor)
end

#lt(other) ⇒ Object



126
127
128
129
130
131
# File 'lib/kmat/logical.rb', line 126

def lt(other)
  unless other.kind_of?(Mat) && other.size == self.size
    other = broadcast(other)
  end
  Mat.new(row_size(), col_size(), :bool).lt!(self, other)
end

#maximum(other) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/kmat/arith.rb', line 86

def maximum(other)
  if other.kind_of?(Mat)
    self.dup.maximum!(broadcast(other))
  else
    self.dup.s_maximum!(other)
  end
end

#mean(arg = :all) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/kmat/statistics.rb', line 17

def mean(arg=:all)
  foo = sum(arg)
  if foo.kind_of?(Mat)
    if foo.row_size != self.row_size
      foo.e_div(self.row_size)
    else
      foo.e_div(self.col_size)
    end
  elsif arg.kind_of?(Mat)
    arg.e_div(self.length)
    arg[0, 0]
  else
    foo.quo(self.length)
  end
end

#minimum(other) ⇒ Object



93
94
95
96
97
98
99
# File 'lib/kmat/arith.rb', line 93

def minimum(other)
  if other.kind_of?(Mat)
    self.dup.minimum!(broadcast(other))
  else
    self.dup.s_minimum!(other)
  end
end

#norm(type = :two, elementwise: false) ⇒ Object

matrix norm ‘type’ Symbol or Integer specifies norm definition if ‘elementwise’ is true, return induced norm if ‘elementwise’ is false, return elementwise norm if ‘type’ is :fro, return Frobenius norm



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/kmat/linalg.rb', line 241

def norm(type=:two, elementwise: false)
  if elementwise
    case type
    when :one, :o, 1
      norm_e1()
    when :infinity, :i, :inf, :infty, Float::INFINITY
      norm_einf()
    when :two, :t, 2, :frobenius, :f, :fro
      normf()
    end
  else
    case type
    when :one, :o, 1
      norm1()
    when :infinity, :i, :inf, :infty, Float::INFINITY
      normi()
    when :two, :t, 2
      norm2()
    when :frobenius, :f, :fro
      normf()
    end
  end
end

#normalizeObject



65
66
67
# File 'lib/kmat/misc.rb', line 65

def normalize
  self.dup.normalize!
end

#normalize!Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/kmat/misc.rb', line 51

def normalize!
  if self.vector?
    self.s_div!(self.normf)
  elsif self.square?
    ev = self.eigen_values
    if ev[0] < 0
      self.diag.s_add!(ev[0]*(-2))
      ev.s_add!(ev[0]*(-2))
    end
    self.s_div!(Math.exp(ev.log!.mean))
  else
    raise MismatchedDimensionError, "normalize is available only for vectors or square matricies"
  end
end

#over(other) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/kmat/linalg.rb', line 95

def over(other)
  if other.square?
    begin
      other.tsolve(self).t!
    rescue UncomputableMatrixError
      other.tls(self).t!
    end
  else
    other.tls(self).t!
  end
end

#over!(a, b) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/kmat/linalg.rb', line 106

def over!(a, b)
  if b.square?
    begin
      tsolve!(b, a).t!
    rescue UncomputableMatrixError
      tls!(b, a).t!
    end
  else
    tls!(b, a).t!
  end
end

#pinvObject



117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/kmat/linalg.rb', line 117

def pinv
  n = self.size.min
  i = Mat.I(n)
  if square?
    begin
      solve(i)
    rescue UncomputableMatrixError
      ls(i)
    end
  else
    ls(i)
  end
end

#pow(other) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/kmat/arith.rb', line 101

def pow(other)
  if other.kind_of?(Mat)
    self.dup.pow!(broadcast(other))
  else
    self.dup.s_pow!(other)
  end
end

#rand(arg = nil, random: $MatRandom) ⇒ Object



92
93
94
# File 'lib/kmat/random.rb', line 92

def rand(arg=nil, random: $MatRandom)
  _rand0(random, arg)
end

#rand_orth(random: $MatRandom) ⇒ Object



66
67
68
# File 'lib/kmat/linalg.rb', line 66

def rand_orth(random: $MatRandom)
  _rand_orth(random)
end

#randn(random: $MatRandom) ⇒ Object



95
96
97
# File 'lib/kmat/random.rb', line 95

def randn(random: $MatRandom)
  _randn0(random)
end

#rcond(type = :two) ⇒ Object



265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/kmat/linalg.rb', line 265

def rcond(type=:two)
  case type
  when :one, :o, 1
    _rcondoi(:one)
  when :infinity, :i, :inf, :infty, Float::INFINITY
    _rcondoi(:infinity)
  when :two, :t, 2
    _rcond2()
  when :frobenius, :f, :fro
    _rcondf()
  end
end

#replace_rep(src) ⇒ Object

replace self by repeated ‘src’ self will be left-top of infinitly repeated ‘src’



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/kmat/accessor.rb', line 71

def replace_rep(src)
  ri = Mat.new(row_size(), 1, :int) do |i, j|
    i % src.row_size
  end
  ci = Mat.new(col_size(), 1, :int) do |i, j|
    i % src.col_size
  end
  src[ri, ci] do |m|
    self.copy_from(m)
  end
end

#repmat(row_repeat, col_repeat) ⇒ Object

for example, A.repmat(2, 3) returns [A, A, A: A, A, A]



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/kmat/accessor.rb', line 28

def repmat(row_repeat, col_repeat)
  ri = Mat.new(row_size()*row_repeat, 1, :int) do |i, j|
    i % row_size()
  end
  ci = Mat.new(col_size()*col_repeat, 1, :int) do |i, j|
    i % col_size()
  end
  self[ri, ci] do |m|
    m.dup
  end
end

#rpow(other) ⇒ Object



108
109
110
# File 'lib/kmat/arith.rb', line 108

def rpow(other)
  other.dup.pow!(other.broadcast(self))
end

#save(file) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/kmat/misc.rb', line 24

def save(file)
  case file
  when String
    File.open(file, 'w') do |f|
      Marshal.dump(self, f)
    end
  when IO
    Marshal.dump(self, file)
  else
    raise ArgumentError, 'the argument must be a filepath or an IO object'
  end
  nil
end

#scalar(alpha) ⇒ Object



66
67
68
# File 'lib/kmat/arith.rb', line 66

def scalar(alpha)
  self.dup.s_mul!(alpha)
end

#squared_distance(other) ⇒ Object



232
233
234
# File 'lib/kmat/linalg.rb', line 232

def squared_distance(other)
  self.dup.sub!(other).iprod
end

#std(arg = :all, ddof: 0) ⇒ Object Also known as: stddev, standard_deviation



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/kmat/statistics.rb', line 73

def std(arg=:all, ddof: 0)
  foo = var(arg, ddof: ddof)
  if foo.kind_of?(Mat)
    foo.sqrt!
  elsif arg.kind_of?(Mat)
    arg.sqrt!
    arg[0, 0]
  else
    Math.sqrt(arg)
  end
end

#sub(other) ⇒ Object Also known as: -



19
20
21
22
23
24
25
# File 'lib/kmat/arith.rb', line 19

def sub(other)
  if other.kind_of?(Mat)
    self.dup.sub!(broadcast(other))
  else
    self.dup.s_sub!(other)
  end
end

#sum(arg = :all) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/kmat/statistics.rb', line 2

def sum(arg=:all)
  case arg
  when Mat
    _sum(arg)
  when :all, :a
    _sum(Mat.new(1, 1, self.vtype))
  when :col, :c
    _sum(Mat.new(1, col_size, self.vtype))
  when :row, :r
    _sum(Mat.new(row_size, 1, self.vtype))
  when :none, :n
    self.dup
  end
end

#tempObject



21
22
23
24
25
# File 'lib/kmat/accessor.rb', line 21

def temp
  ret = yield(self)
  _kill
  ret
end

#under(other) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/kmat/linalg.rb', line 73

def under(other)
  if square?
    begin
      solve(other)
    rescue UncomputableMatrixError
      ls(other)
    end
  else
    ls(other)
  end
end

#under!(a, b) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/kmat/linalg.rb', line 84

def under!(a, b)
  if a.square?
    begin
      solve!(a, b)
    rescue UncomputableMatrixError
      ls!(a, b)
    end
  else
    ls!(a, b)
  end
end

#var(arg = :all, ddof: 0) ⇒ Object Also known as: variance



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/kmat/statistics.rb', line 48

def var(arg=:all, ddof: 0)
  foo = mean(arg)
  if foo.kind_of?(Mat)
    bar = foo.repmat(self.row_size.div(foo.col_size), self.col_size.div(foo.col_size))
    bar.sub!(self).e_mul!(bar)
  else
    unless arg.kind_of?(Mat)
      arg = Mat.new(1, 1, self.vtype) do
        foo
      end
    end
    bar = Mat.new(self.row_size, self.col_size, self.vtype)
    bar.fill(foo)
  end
  bar.sub!(self)
  bar.e_mul!(bar)
  bar.__send__(:_mean, arg, ddof)
  if foo.kind_of?(Mat)
    bar
  else
    bar[0, 0]
  end
end

#wls(b, w) ⇒ Object



62
63
64
# File 'lib/kmat/linalg.rb', line 62

def wls(b, w)
  Mat.new(self.col_size, 1, :f).wls!(self, b, w)
end

#wls!(a, b, w) ⇒ Object

weighted least squares weight ‘w’ is a vector consists of standard deviations of errors a; (m, n)-matrix b: m-vector x: n-vector



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/kmat/linalg.rb', line 49

def wls!(a, b, w)
  nw = w.length
  diag = Mat.new(nw, nw, :f)
  diag.diag.temp do |dd|
    begin
      dd.copy_from(w)
    rescue MismatchedDimensionError
      dd.tcopy_from(w)
    end
    dd.sqrt!
  end
  glm!(a, diag, b)
end