Skip to content

Commit 96a723c

Browse files
committed
Merge pull request #503 from sujithvm/issue_439
Adds simple adjugate function, fixes #439.
2 parents c48a3a1 + 19cb8f6 commit 96a723c

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

lib/nmatrix/math.rb

+49
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,55 @@ def invert
112112
end
113113
alias :inverse :invert
114114

115+
#
116+
# call-seq:
117+
# adjugate! -> NMatrix
118+
#
119+
# Calculate the adjugate of the matrix (in-place).
120+
# Only works on dense matrices.
121+
#
122+
# * *Raises* :
123+
# - +StorageTypeError+ -> only implemented on dense matrices.
124+
# - +ShapeError+ -> matrix must be square.
125+
# - +DataTypeError+ -> cannot calculate adjugate of an integer matrix in-place.
126+
#
127+
def adjugate!
128+
raise(StorageTypeError, "adjugate only works on dense matrices currently") unless self.dense?
129+
raise(ShapeError, "Cannot calculate adjugate of a non-square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1]
130+
raise(DataTypeError, "Cannot calculate adjugate of an integer matrix in-place") if self.integer_dtype?
131+
d = self.det
132+
self.invert!
133+
self.map! { |e| e * d }
134+
self
135+
end
136+
alias :adjoint! :adjugate!
137+
138+
#
139+
# call-seq:
140+
# adjugate -> NMatrix
141+
#
142+
# Make a copy of the matrix and calculate the adjugate of the matrix.
143+
# Only works on dense matrices.
144+
#
145+
# * *Returns* :
146+
# - A dense NMatrix. Will be the same type as the input NMatrix,
147+
# except if the input is an integral dtype, in which case it will be a
148+
# :float64 NMatrix.
149+
#
150+
# * *Raises* :
151+
# - +StorageTypeError+ -> only implemented on dense matrices.
152+
# - +ShapeError+ -> matrix must be square.
153+
#
154+
def adjugate
155+
raise(StorageTypeError, "adjugate only works on dense matrices currently") unless self.dense?
156+
raise(ShapeError, "Cannot calculate adjugate of a non-square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1]
157+
d = self.det
158+
mat = self.invert
159+
mat.map! { |e| e * d }
160+
mat
161+
end
162+
alias :adjoint :adjugate
163+
115164
#
116165
# call-seq:
117166
# getrf! -> Array

spec/math_spec.rb

+43
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,49 @@
478478
end
479479
end
480480

481+
ALL_DTYPES.each do |dtype|
482+
next if dtype == :byte #doesn't work for unsigned types
483+
next if dtype == :object
484+
485+
context dtype do
486+
err = case dtype
487+
when :float32, :complex64
488+
1e-4
489+
else #integer matrices will return :float64
490+
1e-13
491+
end
492+
493+
it "should correctly find adjugate a matrix in place (bang)" do
494+
a = NMatrix.new(:dense, 2, [2, 3, 3, 5], dtype)
495+
b = NMatrix.new(:dense, 2, [5, -3, -3, 2], dtype)
496+
497+
if a.integer_dtype?
498+
expect{a.adjugate!}.to raise_error(DataTypeError)
499+
else
500+
#should return adjugate as well as modifying a
501+
r = a.adjugate!
502+
expect(a).to be_within(err).of(b)
503+
expect(r).to be_within(err).of(b)
504+
end
505+
end
506+
507+
508+
it "should correctly find adjugate of a matrix out-of-place" do
509+
a = NMatrix.new(:dense, 3, [-3, 2, -5, -1, 0, -2, 3, -4, 1], dtype)
510+
511+
if a.integer_dtype?
512+
b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], :float64)
513+
else
514+
b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], dtype)
515+
end
516+
517+
expect(a.adjoint).to be_within(err).of(b)
518+
expect(a.adjugate).to be_within(err).of(b)
519+
end
520+
521+
end
522+
end
523+
481524
# TODO: Get it working with ROBJ too
482525
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype|
483526
[:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype|

0 commit comments

Comments
 (0)