# Matrix Algebra Triplet
#
# by Shin-ichiro Hara
#
# Version 1.0 (2001.11.01)
require "algebra/gaussian-elimination"
require "algebra/elementary-divisor"
module Algebra
class MatrixAlgebra
def to_triplet
Algebra::MatrixAlgebraTriplet.new(self)
end
def to_quint
Algebra::MatrixAlgebraQuint.new(self)
end
end
class MatrixAlgebraTriplet
include GaussianElimination
include ElementaryDivisor
attr_reader :left, :body, :right, :ground
def initialize(matrix, left = nil, right = nil)
@body = matrix
@type = @body.class
@ground = @type.ground
@left_type = Algebra.SquareMatrix(@type.ground, @type.rsize)
@right_type = Algebra.SquareMatrix(@type.ground, @type.csize)
@left = left ? left : @left_type.unity
@right = right ? right : @right_type.unity
end
def to_ary
[body, left, right]
end
alias to_a to_ary
def dup
self.class.new(body.dup, left.dup, right.dup)
end
def transpose
self.class.new(body.transpose, right.transpose, left.transpose)
end
def replace(other)
initialize(other.body, other.left, other.right)
self
end
def display
puts "============= begin"
@left.display
puts
@body.display
puts
@right.display
puts "============= end"
end
def [](i, j)
@body[i, j]
end
def rsize
@body.rsize
end
def csize
@body.csize
end
def each_i(&block)
@body.each_i(&block)
end
def each_j(&block)
@body.each_j(&block)
end
def row!(i)
@body.row!(i)
end
#ElementaryOpeartion
def sswap_r!(i, j)
@left.sswap_r!(i, j)
@body.sswap_r!(i, j)
self
end
def swap_r!(i, j)
@left.swap_r!(i, j)
@body.swap_r!(i, j)
self
end
# def swap_r(i, j)
# dup.swap_r!(i, j)
# end
def swap_c!(i, j)
@body.swap_c!(i, j)
@right.swap_c!(i, j)
self
end
# def swap_c(i, j)
# dup.swap_c!(i, j)
# end
def multiply_r!(i, c)
@left.multiply_r!(i, c)
@body.multiply_r!(i, c)
self
end
# def multiply_r(i, c)
# dup.multiply_r!(i, c)
# end
def multiply_c!(j, c)
@body.multiply_c!(j, c)
@right.multiply_c!(j, c)
self
end
# def multiply_c(j, c)
# dup.multiply_c!(j, c)
# end
def divide_r!(i, c)
@left.divide_r!(i, c)
@body.divide_r!(i, c)
end
# def divide_r(i, c)
# dup.divide_r!(i, c)
# end
def divide_c!(j, c)
@body.divide_c!(j, c)
@right.divide_c!(j, c)
end
# def divide_c(j, c)
# dup.divide_c!(j, c)
# end
def mix_r!(i, j, c = nil)
@left.mix_r!(i, j, c)
@body.mix_r!(i, j, c)
self
end
# def mix_r(i, j, c = nil)
# dup.mix_r!(i, j, c)
# end
def mix_c!(i, j, c = nil)
@body.mix_c!(i, j, c)
@right.mix_c!(i, j, c)
self
end
# def mix_c(i, j, c = nil)
# dup.mix_c!(i, j, c)
# end
def left_eliminate!
# inv = Algebra.SquareMatrix(ground, rsize).unity
k = ground.unity
pi = 0
each_j do |j|
if i = (pi...rsize).find{|i| !self[i, j].zero?}
if i != pi
swap_r!(pi, i)#; inv.swap_r!(pi, i)
k = -k
end
c = ground.unity / self[pi, j] # this lets the entries be in ground
multiply_r!(pi, c)#; inv.multiply_r!(pi, c)
k = k * c
each_i do |i0|
next if i0 == pi
d = self[i0, j]# / self[pi, j]
mix_r!(i0, pi, -d)#; inv.mix_r!(i0, pi, -d)
end
pi += 1
end
end
[left, k]
end
end
class MatrixAlgebraQuint < MatrixAlgebraTriplet
attr_reader :lefti, :righti
def initialize(matrix, left = nil, right = nil, lefti = nil, righti = nil)
super(matrix, left, right)
@lefti = lefti ? lefti : @left_type.unity
@righti = righti ? righti : @right_type.unity
end
def to_ary
[body, left, right, lefti, righti]
end
alias to_a to_ary
def dup
self.class.new(body.dup, left.dup, right.dup, lefti.dup, righti.dup)
end
def transpose
self.class.new(body.transpose, right.transpose, left.transpose,
righti.transpose, lefti.transpose)
end
def replace(other)
initialize(other.body, other.left, other.right, other.lefti, other.righti)
self
end
#ElementaryOpeartion
def sswap_r!(i, j)
@lefti.swap_c!(i, j) # sswap_c doesn't exist
super
end
def swap_r!(i, j)
@lefti.swap_c!(i, j)
super
end
def swap_c!(i, j)
@righti.swap_r!(i, j)
super
end
def multiply_r!(i, c)
@lefti.divide_c!(i, c)
super
end
def multiply_c!(j, c)
@righti.divide_r!(j, c)
super
end
def divide_r!(i, c)
@lefti.multiply_c!(i, c)
super
end
def divide_c!(j, c)
@righti.multiply_r!(j, c)
super
end
def mix_r!(i, j, c = nil)
@lefti.mix_c!(j, i, c ? -c : -1)
super
end
def mix_c!(i, j, c = nil)
@righti.mix_r!(j, i, c ? -c : -1)
super
end
end
end
if $0 == __FILE__
require "algebra/m-polynomial"
require "algebra/polynomial"
require "algebra/rational"
require "algebra/matrix-algebra"
# class Rational# < Numeric
# def inspect; to_s; end
# end
# include Algebra
G = Algebra.MatrixAlgebra(Rational, 2, 2)
a = G[[1, 1], [1, -1]]
a0 = Algebra::MatrixAlgebraTriplet.new(a)
a0.display
a0.left_eliminate!
puts "-------"
a0.display
# p a.kernel_basis
end
syntax highlighted by Code2HTML, v. 0.9.1