Format code

This commit is contained in:
Chris Watson 2019-09-10 19:08:28 -07:00
parent b11731a824
commit 1e0d809535
5 changed files with 86 additions and 83 deletions

View File

@ -32,8 +32,8 @@ describe "Apatite::Vector" do
describe ".independent?" do describe ".independent?" do
it "returns true if all of vectors are linearly independent" do it "returns true if all of vectors are linearly independent" do
Apatite::Vector.independent?(Apatite::Vector[1,0], Apatite::Vector[0,1]).should be_true Apatite::Vector.independent?(Apatite::Vector[1, 0], Apatite::Vector[0, 1]).should be_true
Apatite::Vector.independent?(Apatite::Vector[1,2], Apatite::Vector[2,4]).should be_false Apatite::Vector.independent?(Apatite::Vector[1, 2], Apatite::Vector[2, 4]).should be_false
end end
end end

View File

@ -7,5 +7,4 @@ require "./apatite/*"
# of NumPy sitting atop the blazing speed and beautiful syntax # of NumPy sitting atop the blazing speed and beautiful syntax
# of Crystal. # of Crystal.
module Apatite module Apatite
end end

View File

@ -1,7 +1,11 @@
module Apatite module Apatite
class Error < Exception; end class Error < Exception; end
class ErrDimensionMismatch < Error; end class ErrDimensionMismatch < Error; end
class ZeroVectorError < Error; end class ZeroVectorError < Error; end
class ErrNotRegular < Error; end class ErrNotRegular < Error; end
class ErrOperationNotDefined < Error; end class ErrOperationNotDefined < Error; end
end end

View File

@ -165,7 +165,7 @@ module Apatite
# `row`. # `row`.
# #
# ``` # ```
# Matrix.row_vector([4,5,6]) # Matrix.row_vector([4, 5, 6])
# # => [ 4, 5, 6 ] # # => [ 4, 5, 6 ]
# ``` # ```
def self.row_vector(row) def self.row_vector(row)
@ -177,7 +177,7 @@ module Apatite
# in `column`. # in `column`.
# #
# ``` # ```
# Matrix.column_vector([4,5,6]) # Matrix.column_vector([4, 5, 6])
# # => [ 4, # # => [ 4,
# # 5, # # 5,
# # 6 ] # # 6 ]
@ -258,7 +258,7 @@ module Apatite
# ``` # ```
# x = Matrix[[6, 6], [4, 4]] # x = Matrix[[6, 6], [4, 4]]
# y = Matrix[[1, 2], [3, 4]] # y = Matrix[[1, 2], [3, 4]]
# Matrix.combine(x, y) {|a, b| a - b} # Matrix.combine(x, y) { |a, b| a - b }
# # => Matrix[[5, 4], [1, 0]] # # => Matrix[[5, 4], [1, 0]]
# ``` # ```
def self.combine(*matrices, &block) def self.combine(*matrices, &block)
@ -272,7 +272,7 @@ module Apatite
rows = Array(T).new(x.row_count) do |i| rows = Array(T).new(x.row_count) do |i|
Array(T).new(x.column_count) do |j| Array(T).new(x.column_count) do |j|
yield matrices.map{ |m| m[i,j] } yield matrices.map { |m| m[i, j] }
end end
end end
@ -396,9 +396,9 @@ module Apatite
# * :upper: yields only elements on or above the diagonal # * :upper: yields only elements on or above the diagonal
# #
# ``` # ```
# Matrix[ [1,2], [3,4] ].each { |e| puts e } # Matrix[[1, 2], [3, 4]].each { |e| puts e }
# # => prints the numbers 1 to 4 # # => prints the numbers 1 to 4
# Matrix[ [1,2], [3,4] ].each(:strict_lower).to_a # => [3] # Matrix[[1, 2], [3, 4]].each(:strict_lower).to_a # => [3]
# ``` # ```
def each(which = :all, &block : T ->) def each(which = :all, &block : T ->)
last = column_count last = column_count
@ -409,7 +409,7 @@ module Apatite
end end
when "diagonal" when "diagonal"
@rows.each_with_index do |row, row_index| @rows.each_with_index do |row, row_index|
yield row.fetch(row_index){ return self } yield row.fetch(row_index) { return self }
end end
when "off_diagonal" when "off_diagonal"
@rows.each_with_index do |row, row_index| @rows.each_with_index do |row, row_index|
@ -431,7 +431,7 @@ module Apatite
end end
when "strict_upper" when "strict_upper"
@rows.each_with_index do |row, row_index| @rows.each_with_index do |row, row_index|
(row_index+1).upto(last - 1) do |col_index| (row_index + 1).upto(last - 1) do |col_index|
yield row[col_index] yield row[col_index]
end end
end end
@ -449,7 +449,7 @@ module Apatite
# Same as #each, but the row index and column index in addition to the element # Same as #each, but the row index and column index in addition to the element
# #
# ``` # ```
# Matrix[ [1,2], [3,4] ].each_with_index do |e, row, col| # Matrix[[1, 2], [3, 4]].each_with_index do |e, row, col|
# puts "#{e} at #{row}, #{col}" # puts "#{e} at #{row}, #{col}"
# end # end
# # => Prints: # # => Prints:
@ -469,7 +469,7 @@ module Apatite
end end
when "diagonal" when "diagonal"
@rows.each_with_index do |row, row_index| @rows.each_with_index do |row, row_index|
block.call(row.fetch(row_index){return self}, row_index, row_index) block.call(row.fetch(row_index) { return self }, row_index, row_index)
end end
when "off_diagonal" when "off_diagonal"
@rows.each_with_index do |row, row_index| @rows.each_with_index do |row, row_index|
@ -491,7 +491,7 @@ module Apatite
end end
when "strict_upper" when "strict_upper"
@rows.each_with_index do |row, row_index| @rows.each_with_index do |row, row_index|
(row_index+1).upto(last - 1) do |col_index| (row_index + 1).upto(last - 1) do |col_index|
block.call(row[col_index], row_index, col_index) block.call(row[col_index], row_index, col_index)
end end
end end
@ -512,7 +512,7 @@ module Apatite
# It also accepts an optional `selector` argument, see `#each` for details. # It also accepts an optional `selector` argument, see `#each` for details.
# #
# ``` # ```
# Matrix[ [1,1], [1,1] ].index(1, :strict_lower) # Matrix[[1, 1], [1, 1]].index(1, :strict_lower)
# # => {1, 0} # # => {1, 0}
# ``` # ```
def index(i, selector = :all) def index(i, selector = :all)
@ -531,7 +531,7 @@ module Apatite
# `#each` for details. # `#each` for details.
# #
# ``` # ```
# Matrix[ [1,2], [3,4] ].index(&.even?) # Matrix[[1, 2], [3, 4]].index(&.even?)
# # => {0, 1} # # => {0, 1}
# ``` # ```
def index(selector = :all, &block : T -> Bool) def index(selector = :all, &block : T -> Bool)
@ -656,7 +656,7 @@ module Apatite
# Returns the Laplace expansion along given row or column. # Returns the Laplace expansion along given row or column.
# #
# ``` # ```
# Matrix[[7,6], [3,9]].laplace_expansion(column: 1) # Matrix[[7, 6], [3, 9]].laplace_expansion(column: 1)
# # => 45 # # => 45
# #
# Matrix[[Vector[1, 0], Vector[0, 1]], [2, 3]].laplace_expansion(row: 0) # Matrix[[Vector[1, 0], Vector[0, 1]], [2, 3]].laplace_expansion(row: 0)
@ -711,9 +711,9 @@ module Apatite
self self
end end
#-- # --
# TESTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # TESTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++ # ++
# Returns `true` if this is a diagonal matrix. # Returns `true` if this is a diagonal matrix.
# #
@ -883,9 +883,9 @@ module Apatite
@rows.flatten.all?(&.zero?) @rows.flatten.all?(&.zero?)
end end
#-- # --
# OBJECT METHODS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # OBJECT METHODS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++ # ++
# Equality operator # Equality operator
def ==(other : Matrix) def ==(other : Matrix)
@ -900,14 +900,14 @@ module Apatite
Matrix.new(@rows.map(&.dup), column_count) Matrix.new(@rows.map(&.dup), column_count)
end end
#-- # --
# ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++ # ++
# Matrix multiplication # Matrix multiplication
# #
# ``` # ```
# Matrix[[2,4], [6,8]] * Matrix.identity(2) # Matrix[[2, 4], [6, 8]] * Matrix.identity(2)
# # => [ 2, 4, # # => [ 2, 4,
# # 6, 8 ] # # 6, 8 ]
# ``` # ```
@ -940,7 +940,7 @@ module Apatite
# Matrix addition # Matrix addition
# #
# ``` # ```
# Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]] # Matrix.scalar(2, 5) + Matrix[[1, 0], [-4, 7]]
# # => [ 6, 0, # # => [ 6, 0,
# # -4, 1 ] # # -4, 1 ]
# ``` # ```
@ -967,7 +967,7 @@ module Apatite
# Matrix subtraction # Matrix subtraction
# #
# ``` # ```
# Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]] # Matrix[[1, 5], [4, 2]] - Matrix[[9, 3], [-4, 1]]
# # => [-8, 2, # # => [-8, 2,
# # 8, 1 ] # # 8, 1 ]
# ``` # ```
@ -994,7 +994,7 @@ module Apatite
# Matrix division (multiplication by the inverse). # Matrix division (multiplication by the inverse).
# #
# ``` # ```
# Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]] # Matrix[[7, 6], [3, 9]] / Matrix[[2, 9], [3, 1]]
# # => [ -7, 1, # # => [ -7, 1,
# # -3, -6 ] # # -3, -6 ]
# ``` # ```
@ -1002,7 +1002,7 @@ module Apatite
case other case other
when Number when Number
rows = @rows.map do |row| rows = @rows.map do |row|
row.map {|e| (e / other).as(T) } row.map { |e| (e / other).as(T) }
end end
return Matrix.new(rows, column_count) return Matrix.new(rows, column_count)
when Matrix when Matrix
@ -1015,12 +1015,12 @@ module Apatite
# Hadamard product # Hadamard product
# #
# ``` # ```
# Matrix[[1,2], [3,4]].hadamard_product Matrix[[1,2], [3,2]] # Matrix[[1, 2], [3, 4]].hadamard_product Matrix[[1, 2], [3, 2]]
# # => [ 1, 4, # # => [ 1, 4,
# # 9, 8 ] # # 9, 8 ]
# ``` # ```
def hadamard_product(m) def hadamard_product(m)
combine(m){ |a, b| a * b } combine(m) { |a, b| a * b }
end end
# Returns the inverse of the matrix. # Returns the inverse of the matrix.
@ -1077,7 +1077,7 @@ module Apatite
# Non integer exponents will be handled by diagonalizing the matrix. # Non integer exponents will be handled by diagonalizing the matrix.
# #
# ``` # ```
# Matrix[[7,6], [3,9]] ** 2 # Matrix[[7, 6], [3, 9]] ** 2
# # => [ 67, 96, # # => [ 67, 96,
# # 48, 99 ] # # 48, 99 ]
# ``` # ```
@ -1085,9 +1085,9 @@ module Apatite
# TODO # TODO
end end
#-- # --
# MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++ # ++
# Returns the determinant of the matrix. # Returns the determinant of the matrix.
# #
@ -1096,7 +1096,7 @@ module Apatite
# Consider using exact types like Rational or BigDecimal instead. # Consider using exact types like Rational or BigDecimal instead.
# #
# ``` # ```
# Matrix[[7,6], [3,9]].determinant # Matrix[[7, 6], [3, 9]].determinant
# # => 45 # # => 45
# ``` # ```
def determinant def determinant
@ -1192,7 +1192,7 @@ module Apatite
# Consider using exact types like Rational or BigDecimal instead. # Consider using exact types like Rational or BigDecimal instead.
# #
# ``` # ```
# Matrix[[7,6], [3,9]].rank # Matrix[[7, 6], [3, 9]].rank
# # => 2 # # => 2
# ``` # ```
def rank def rank
@ -1204,15 +1204,15 @@ module Apatite
pivot_row = 0 pivot_row = 0
previous_pivot = 1 previous_pivot = 1
0.upto(last_column) do |k| 0.upto(last_column) do |k|
switch_row = (pivot_row .. last_row).find {|row| switch_row = (pivot_row..last_row).find { |row|
a[row][k] != 0 a[row][k] != 0
} }
if switch_row if switch_row
a[switch_row], a[pivot_row] = a[pivot_row], a[switch_row] unless pivot_row == switch_row a[switch_row], a[pivot_row] = a[pivot_row], a[switch_row] unless pivot_row == switch_row
pivot = a[pivot_row][k] pivot = a[pivot_row][k]
(pivot_row+1).upto(last_row) do |i| (pivot_row + 1).upto(last_row) do |i|
ai = a[i] ai = a[i]
(k+1).upto(last_column) do |j| (k + 1).upto(last_column) do |j|
ai[j] = (pivot * ai[j] - ai[k] * a[pivot_row][j]) / previous_pivot ai[j] = (pivot * ai[j] - ai[k] * a[pivot_row][j]) / previous_pivot
end end
end end
@ -1226,13 +1226,13 @@ module Apatite
# Returns a matrix with entries rounded to the given precision # Returns a matrix with entries rounded to the given precision
# (see `Float#round`) # (see `Float#round`)
def round(n = 0) def round(n = 0)
map {|e| e.round(n) } map { |e| e.round(n) }
end end
# Returns the trace (sum of diagonal elements) of the matrix. # Returns the trace (sum of diagonal elements) of the matrix.
# #
# ``` # ```
# Matrix[[7,6], [3,9]].trace # Matrix[[7, 6], [3, 9]].trace
# # => 16 # # => 16
# ``` # ```
def trace def trace
@ -1250,11 +1250,11 @@ module Apatite
# Returns the transpose of the matrix. # Returns the transpose of the matrix.
# #
# ``` # ```
# Matrix[[1,2], [3,4], [5,6]] # Matrix[[1, 2], [3, 4], [5, 6]]
# # => [ 1, 2, # # => [ 1, 2,
# # 3, 4, # # 3, 4,
# # 5, 6 ] # # 5, 6 ]
# Matrix[[1,2], [3,4], [5,6]].transpose # Matrix[[1, 2], [3, 4], [5, 6]].transpose
# # => [ 1, 3, 5, # # => [ 1, 3, 5,
# # 2, 4, 6 ] # # 2, 4, 6 ]
# ``` # ```
@ -1281,9 +1281,9 @@ module Apatite
self.class.vstack(self, *matrices) self.class.vstack(self, *matrices)
end end
#-- # --
# DECOMPOSITIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # DECOMPOSITIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#++ # ++
# Returns the Eigensystem of the matrix # Returns the Eigensystem of the matrix
# See `EigenvalueDecomposition`. # See `EigenvalueDecomposition`.
@ -1319,17 +1319,17 @@ module Apatite
LUPDecomposition.new(self) LUPDecomposition.new(self)
end end
#-- # --
# COMPLEX ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # COMPLEX ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#++ # ++
# Returns the conjugate of the matrix. # Returns the conjugate of the matrix.
# #
# ``` # ```
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]] # Matrix[[Complex(1, 2), Complex(0, 1), 0], [1, 2, 3]]
# # => 1+2i i 0 # # => 1+2i i 0
# # 1 2 3 # # 1 2 3
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conj # Matrix[[Complex(1, 2), Complex(0, 1), 0], [1, 2, 3]].conj
# # => 1-2i -i 0 # # => 1-2i -i 0
# # 1 2 3 # # 1 2 3
# ``` # ```
@ -1341,10 +1341,10 @@ module Apatite
# Returns the imaginary part of the matrix. # Returns the imaginary part of the matrix.
# #
# ``` # ```
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]] # Matrix[[Complex(1, 2), Complex(0, 1), 0], [1, 2, 3]]
# # => [ 1+2i, i, 0, # # => [ 1+2i, i, 0,
# # 1, 2, 3 ] # # 1, 2, 3 ]
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imag # Matrix[[Complex(1, 2), Complex(0, 1), 0], [1, 2, 3]].imag
# # => [ 2i, i, 0, # # => [ 2i, i, 0,
# # 0, 0, 0 ] # # 0, 0, 0 ]
# ``` # ```
@ -1356,10 +1356,10 @@ module Apatite
# Returns the real part of the matrix. # Returns the real part of the matrix.
# #
# ``` # ```
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]] # Matrix[[Complex(1, 2), Complex(0, 1), 0], [1, 2, 3]]
# # => [ 1+2i, i, 0, # # => [ 1+2i, i, 0,
# # 1, 2, 3 ] # # 1, 2, 3 ]
# Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real # Matrix[[Complex(1, 2), Complex(0, 1), 0], [1, 2, 3]].real
# # => [ 1, 0, 0, # # => [ 1, 0, 0,
# # 1, 2, 3 ] # # 1, 2, 3 ]
# ``` # ```
@ -1380,9 +1380,9 @@ module Apatite
[real, imag] [real, imag]
end end
#-- # --
# CONVERTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # CONVERTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++ # ++
# Attempt to coerce the elements in the matrix to another type. # Attempt to coerce the elements in the matrix to another type.
def coerce(klass) def coerce(klass)
@ -1392,14 +1392,14 @@ module Apatite
# Returns an array of the row vectors of the matrix. See `Vector`. # Returns an array of the row vectors of the matrix. See `Vector`.
def row_vectors def row_vectors
Array.new(row_count) {|i| Array.new(row_count) { |i|
row(i) row(i)
} }
end end
# Returns an array of the column vectors of the matrix. See `Vector`. # Returns an array of the column vectors of the matrix. See `Vector`.
def column_vectors def column_vectors
Array.new(column_count) {|i| Array.new(column_count) { |i|
column(i) column(i)
} }
end end
@ -1426,9 +1426,9 @@ module Apatite
self self
end end
#-- # --
# PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#++ # ++
def to_s(io) def to_s(io)
if empty? if empty?

View File

@ -43,10 +43,10 @@ module Apatite
# Returns `true` if all of vectors are linearly independent. # Returns `true` if all of vectors are linearly independent.
# #
# ``` # ```
# Vector.independent?(Vector[1,0], Vector[0,1]) # Vector.independent?(Vector[1, 0], Vector[0, 1])
# # => true # # => true
# #
# Vector.independent?(Vector[1,2], Vector[2,4]) # Vector.independent?(Vector[1, 2], Vector[2, 4])
# # => false # # => false
# ``` # ```
def self.independent?(*vs) def self.independent?(*vs)
@ -167,7 +167,7 @@ module Apatite
prod = magnitude * v.magnitude prod = magnitude * v.magnitude
raise ZeroVectorError.new("Can't get angle of zero vector") if prod == 0 raise ZeroVectorError.new("Can't get angle of zero vector") if prod == 0
Math.acos( inner_product(v) / prod ) Math.acos(inner_product(v) / prod)
end end
# Returns a copy of the vector. # Returns a copy of the vector.
@ -210,11 +210,11 @@ module Apatite
Vector[-@elements[1], @elements[0]] Vector[-@elements[1], @elements[0]]
when 3 when 3
v = vs[0] v = vs[0]
Vector[ v[2]*@elements[1] - v[1]*@elements[2], Vector[v[2]*@elements[1] - v[1]*@elements[2],
v[0]*@elements[2] - v[2]*@elements[0], v[0]*@elements[2] - v[2]*@elements[0],
v[1]*@elements[0] - v[0]*@elements[1] ] v[1]*@elements[0] - v[0]*@elements[1]]
else else
rows = [self, vs.to_a, Array.new(size) {|i| Vector.basis(size, i) }].flatten rows = [self, vs.to_a, Array.new(size) { |i| Vector.basis(size, i) }].flatten
Matrix.rows(rows).laplace_expansion(row: size - 1) Matrix.rows(rows).laplace_expansion(row: size - 1)
end end
end end
@ -268,7 +268,7 @@ module Apatite
# Returns a vector with entries rounded to the given precision. # Returns a vector with entries rounded to the given precision.
def round(ndigits = 0) def round(ndigits = 0)
map{ |e| e.round(ndigits) } map { |e| e.round(ndigits) }
end end
# Attempt to coerce the elements in a vector to Complex with # Attempt to coerce the elements in a vector to Complex with