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