Matrix Multiplication Program in Ruby

Matrix Multiplication

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.