RosettaCodeData/Task/Strassens-algorithm/Lua/strassens-algorithm.lua

242 lines
6.1 KiB
Lua
Raw Permalink Normal View History

2026-04-30 12:34:36 -04:00
-- Helper function to create a matrix from nested blocks
local function block_matrix(blocks)
local m = {}
local num_hblocks = #blocks
local num_vblocks = #blocks[1]
-- Determine dimensions
local block_height = #blocks[1][1]
local block_widths = {}
for j = 1, num_vblocks do
block_widths[j] = #blocks[1][j][1]
end
-- Build the resulting matrix
for i = 1, block_height * num_hblocks do
m[i] = {}
end
for h = 1, num_hblocks do
local row_offset = (h - 1) * block_height
for i = 1, block_height do
local col_offset = 0
for v = 1, num_vblocks do
local block = blocks[h][v]
for j = 1, block_widths[v] do
m[row_offset + i][col_offset + j] = block[i][j]
end
col_offset = col_offset + block_widths[v]
end
end
end
return m
end
-- Matrix multiplication (naive)
local function matrix_multiply(a, b)
local rows_a, cols_a = #a, #a[1]
local rows_b, cols_b = #b, #b[1]
assert(cols_a == rows_b, "Incompatible matrix dimensions for multiplication")
local result = {}
for i = 1, rows_a do
result[i] = {}
for j = 1, cols_b do
local sum = 0
for k = 1, cols_a do
sum = sum + a[i][k] * b[k][j]
end
result[i][j] = sum
end
end
return result
end
-- Matrix addition
local function matrix_add(a, b)
local rows, cols = #a, #a[1]
assert(rows == #b and cols == #b[1], "Matrices must have the same dimensions")
local result = {}
for i = 1, rows do
result[i] = {}
for j = 1, cols do
result[i][j] = a[i][j] + b[i][j]
end
end
return result
end
-- Matrix subtraction
local function matrix_subtract(a, b)
local rows, cols = #a, #a[1]
assert(rows == #b and cols == #b[1], "Matrices must have the same dimensions")
local result = {}
for i = 1, rows do
result[i] = {}
for j = 1, cols do
result[i][j] = a[i][j] - b[i][j]
end
end
return result
end
-- Get submatrix
local function get_submatrix(m, start_row, end_row, start_col, end_col)
local result = {}
for i = start_row, end_row do
local row = {}
for j = start_col, end_col do
table.insert(row, m[i][j])
end
table.insert(result, row)
end
return result
end
-- Strassen's algorithm
local function strassen_multiply(a, b)
local n = #a
local m = #a[1]
assert(n == m, "Matrix must be square")
assert(n == #b and n == #b[1], "Matrices must have the same dimensions")
-- Check if size is a power of 2
local temp = n
while temp > 1 do
assert(temp % 2 == 0, "Matrix dimension must be a power of 2")
temp = temp / 2
end
if n == 1 then
return {{a[1][1] * b[1][1]}}
end
local half = n // 2
-- Partition matrices into quadrants
local a11 = get_submatrix(a, 1, half, 1, half)
local a12 = get_submatrix(a, 1, half, half+1, n)
local a21 = get_submatrix(a, half+1, n, 1, half)
local a22 = get_submatrix(a, half+1, n, half+1, n)
local b11 = get_submatrix(b, 1, half, 1, half)
local b12 = get_submatrix(b, 1, half, half+1, n)
local b21 = get_submatrix(b, half+1, n, 1, half)
local b22 = get_submatrix(b, half+1, n, half+1, n)
-- Calculate the seven products
local m1 = strassen_multiply(matrix_add(a11, a22), matrix_add(b11, b22))
local m2 = strassen_multiply(matrix_add(a21, a22), b11)
local m3 = strassen_multiply(a11, matrix_subtract(b12, b22))
local m4 = strassen_multiply(a22, matrix_subtract(b21, b11))
local m5 = strassen_multiply(matrix_add(a11, a12), b22)
local m6 = strassen_multiply(matrix_subtract(a21, a11), matrix_add(b11, b12))
local m7 = strassen_multiply(matrix_subtract(a12, a22), matrix_add(b21, b22))
-- Calculate the four quadrants of the result
local c11 = matrix_add(matrix_subtract(matrix_add(m1, m4), m5), m7)
local c12 = matrix_add(m3, m5)
local c21 = matrix_add(m2, m4)
local c22 = matrix_add(matrix_subtract(matrix_add(m1, m3), m2), m6)
-- Combine quadrants into a single matrix
return block_matrix({{c11, c12}, {c21, c22}})
end
-- Round matrix values
local function matrix_round(m, digits)
local result = {}
local mult = 10^digits
for i = 1, #m do
result[i] = {}
for j = 1, #m[1] do
if digits then
result[i][j] = math.floor(m[i][j] * mult + 0.5) / mult
else
result[i][j] = math.floor(m[i][j] + 0.5)
end
end
end
return result
end
-- Print matrix
local function print_matrix(name, m)
print(name .. " = {")
for i = 1, #m do
io.write(" {")
for j = 1, #m[1] do
io.write(m[i][j])
if j < #m[1] then
io.write(", ")
end
end
print("}")
end
print("}")
end
-- Examples
local function run_examples()
local a = {
{1, 2},
{3, 4}
}
local b = {
{5, 6},
{7, 8}
}
local c = {
{1, 1, 1, 1},
{2, 4, 8, 16},
{3, 9, 27, 81},
{4, 16, 64, 256}
}
local d = {
{4, -3, 4/3, -1/4},
{-13/3, 19/4, -7/3, 11/24},
{3/2, -2, 7/6, -1/4},
{-1/6, 1/4, -1/6, 1/24}
}
local e = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
}
local f = {
{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1}
}
print("Naive matrix multiplication:")
print_matrix(" a * b", matrix_multiply(a, b))
print_matrix(" c * d", matrix_round(matrix_multiply(c, d), 0))
print_matrix(" e * f", matrix_multiply(e, f))
print("\nStrassen's matrix multiplication:")
print_matrix(" a * b", strassen_multiply(a, b))
print_matrix(" c * d", matrix_round(strassen_multiply(c, d), 0))
print_matrix(" e * f", strassen_multiply(e, f))
end
-- Run examples
run_examples()