Matrix Multiplication Program in Ruby
Introduction
Matrix multiplication is a fundamental operation in many fields, including computer graphics, machine learning, and scientific computing. Understanding how to implement matrix multiplication efficiently can enhance your programming skills and deepen your understanding of linear algebra. In this article, we’ll explore how to write a matrix multiplication program in Ruby, a dynamic and expressive programming language. We’ll cover the basic concepts of matrix multiplication, write the Ruby code step-by-step, and discuss potential optimizations and enhancements.
Creating a Simple Library Management System in Ruby
Understanding Matrix Multiplication
Before diving into the code, let’s review the basics of matrix multiplication. Given two matrices, A and B, the product matrix C is calculated by taking the dot product of rows from A and columns from B.
For example, if A is a matrix of dimensions (m \times n) and B is a matrix of dimensions (n \times p), their product C will be a matrix of dimensions (m \times p). The element (c_{ij}) in the resulting matrix C is computed as follows:
[ c_{ij} = \sum_{k=1}^{n} a_{ik} \cdot b_{kj} ]
where (a_{ik}) is the element in the ith row and kth column of matrix A, and (b_{kj}) is the element in the kth row and jth column of matrix B.
Setting Up the Ruby Environment
Ensure that Ruby is installed on your system. You can check the version or install Ruby using a version manager like RVM (Ruby Version Manager) or through the official Ruby website.
$ ruby -v
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin20]
If Ruby is not installed, you can install it using RVM:
$ \curl -sSL https://get.rvm.io | bash -s stable
$ rvm install ruby
$ rvm use ruby --default
$ ruby -v
Creating the Matrix Multiplication Program
Let’s start by creating a directory for our project and setting up the main program file:
$ mkdir matrix_multiplication
$ cd matrix_multiplication
$ touch matrix_multiplication.rb
Defining the Matrix Class
We’ll define a Matrix
class to handle matrix operations, including initialization, displaying the matrix, and performing the multiplication.
# matrix_multiplication.rb
class Matrix
attr_accessor :rows, :cols, :data
def initialize(rows, cols, data = nil)
@rows = rows
@cols = cols
@data = data || Array.new(rows) { Array.new(cols, 0) }
end
def [](i, j)
@data[i][j]
end
def []=(i, j, value)
@data[i][j] = value
end
def to_s
@data.map { |row| row.join(' ') }.join("\n")
end
end
Implementing Matrix Multiplication
Next, we’ll implement the matrix multiplication method within the Matrix
class. This method will take another matrix as an argument and return the resulting product matrix.
class Matrix
# Existing code...
def multiply(other)
raise "Incompatible matrices for multiplication" unless @cols == other.rows
result = Matrix.new(@rows, other.cols)
@rows.times do |i|
other.cols.times do |j|
sum = 0
@cols.times do |k|
sum += self[i, k] * other[k, j]
end
result[i, j] = sum
end
end
result
end
end
Testing the Matrix Multiplication
We’ll now add some test cases to ensure our matrix multiplication works correctly. Let’s create two matrices and multiply them using our Matrix
class.
# matrix_multiplication.rb
# Existing code...
# Define the first matrix
matrix_a = Matrix.new(2, 3, [
[1, 2, 3],
[4, 5, 6]
])
# Define the second matrix
matrix_b = Matrix.new(3, 2, [
[7, 8],
[9, 10],
[11, 12]
])
# Perform the multiplication
result_matrix = matrix_a.multiply(matrix_b)
# Display the result
puts "Matrix A:"
puts matrix_a
puts "\nMatrix B:"
puts matrix_b
puts "\nResult of A x B:"
puts result_matrix
Running the Program
To run the program, navigate to the project directory and execute the matrix_multiplication.rb
file:
$ ruby matrix_multiplication.rb
You should see the matrices and the result of their multiplication displayed in the terminal.
Optimizing the Program
Our current implementation works for basic matrix multiplication, but there are several ways to optimize it for better performance and usability.
1. Input Validation
We should add validation to ensure the matrices are correctly formatted and compatible for multiplication.
class Matrix
# Existing code...
def valid_matrix?
@data.is_a?(Array) && @data.all? { |row| row.is_a?(Array) && row.size == @cols }
end
def multiply(other)
raise "Invalid matrix format" unless valid_matrix? && other.valid_matrix?
raise "Incompatible matrices for multiplication" unless @cols == other.rows
# Existing multiplication code...
end
end
2. Handling Non-Numeric Entries
We can add validation to ensure all matrix elements are numeric.
class Matrix
# Existing code...
def numeric_matrix?
@data.flatten.all? { |element| element.is_a?(Numeric) }
end
def multiply(other)
raise "Invalid matrix format" unless valid_matrix? && other.valid_matrix?
raise "Matrix contains non-numeric elements" unless numeric_matrix? && other.numeric_matrix?
raise "Incompatible matrices for multiplication" unless @cols == other.rows
# Existing multiplication code...
end
end
3. Enhanced Display
We can improve the to_s
method to align the matrix elements for better readability.
class Matrix
# Existing code...
def to_s
col_widths = @data.transpose.map { |col| col.map { |el| el.to_s.size }.max }
@data.map { |row| row.map.with_index { |el, idx| el.to_s.ljust(col_widths[idx]) }.join(' ') }.join("\n")
end
end
Adding Additional Features
To make our matrix multiplication program more comprehensive, we can add additional features such as matrix addition, subtraction, and transposition.
1. Matrix Addition
class Matrix
# Existing code...
def add(other)
raise "Matrices dimensions do not match for addition" unless @rows == other.rows && @cols == other.cols
result = Matrix.new(@rows, @cols)
@rows.times do |i|
@cols.times do |j|
result[i, j] = self[i, j] + other[i, j]
end
end
result
end
end
2. Matrix Subtraction
class Matrix
# Existing code...
def subtract(other)
raise "Matrices dimensions do not match for subtraction" unless @rows == other.rows && @cols == other.cols
result = Matrix.new(@rows, @cols)
@rows.times do |i|
@cols.times do |j|
result[i, j] = self[i, j] - other[i, j]
end
end
result
end
end
3. Matrix Transposition
class Matrix
# Existing code...
def transpose
result = Matrix.new(@cols, @rows)
@rows.times do |i|
@cols.times do |j|
result[j, i] = self[i, j]
end
end
result
end
end
Conclusion
Writing a matrix multiplication program in Ruby is a great exercise in understanding both programming and linear algebra. We’ve covered the basic implementation, discussed potential optimizations, and added additional features to enhance the functionality. This project provides a solid foundation for further exploration into more advanced topics such as parallel processing and numerical stability. By continuing to build on this foundation, you can deepen your understanding and improve your skills in both Ruby programming and mathematical computing.