161 lines
5.7 KiB
GDScript
161 lines
5.7 KiB
GDScript
@tool
|
|
extends RefCounted
|
|
class_name MatrixGenerator
|
|
|
|
static func zeros(rows: int, columns: int) -> Matrix:
|
|
var zeros: Array = []
|
|
var t_rows: Array = []
|
|
t_rows.resize(columns)
|
|
t_rows.fill(0.0)
|
|
for row in rows:
|
|
zeros.append(t_rows.duplicate())
|
|
return Matrix.new(zeros)
|
|
|
|
# Generates a Matrix with random values between [from; to] with a given @size (rows, columns)
|
|
static func random_float_range(from : float, to : float, size : Vector2, _seed : int = 1234) -> Matrix:
|
|
seed(_seed)
|
|
randomize()
|
|
var array : Array = []
|
|
for row in range(size.x):
|
|
var matrix_row : Array = []
|
|
for column in range(size.y): matrix_row.append(randf_range(from,to))
|
|
array.append(matrix_row)
|
|
return Matrix.new(array)
|
|
|
|
# Generates a Matrix giving an Array (Array must by Array[Array])
|
|
static func from_array(array : Array = []) -> Matrix:
|
|
var matrix : Array = []
|
|
matrix.append(array)
|
|
return Matrix.new(matrix)
|
|
|
|
# Generates a sub-Matrix giving a Matrix, a @from Array [row_i, column_i] and a @to Array [row_j, column_j]
|
|
static func sub_matrix(_matrix : Matrix, from : PackedInt32Array, to : PackedInt32Array) -> Matrix:
|
|
assert( not (to[0] > _matrix.rows() or to[1] > _matrix.columns()),
|
|
"%s is not an acceptable size for the submatrix, giving a matrix of size %s"%[to, _matrix.get_size()])
|
|
var array : Array = []
|
|
var rows : Array = _matrix.get_rows(from[0], to[0])
|
|
for row in rows:
|
|
array.append(row.slice(from[1], to[1]))
|
|
return Matrix.new(array)
|
|
|
|
# Duplicates a given Matrix
|
|
static func duplicate(_matrix : Matrix) -> Matrix:
|
|
return Matrix.new(_matrix.to_array().duplicate())
|
|
|
|
# Calculate the determinant of a matrix
|
|
static func determinant(matrix: Matrix) -> float:
|
|
assert(matrix.is_square()) #,"Expected square matrix")
|
|
|
|
var determinant: float = 0.0
|
|
|
|
if matrix.rows() == 2 :
|
|
determinant = (matrix.value(0, 0) * matrix.value(1, 1)) - (matrix.value(0, 1) * matrix.value(1, 0))
|
|
elif matrix.is_diagonal() or matrix.is_triangular() :
|
|
for i in matrix.rows():
|
|
determinant *= matrix.value(i, i)
|
|
elif matrix.is_identity() :
|
|
determinant = 1.0
|
|
else:
|
|
# Laplace expansion
|
|
var multiplier: float = -1.0
|
|
var submatrix: Matrix = sub_matrix(matrix, [1, 0], [matrix.rows(), matrix.columns()])
|
|
for j in matrix.columns() :
|
|
var cofactor: Matrix = copy(submatrix)
|
|
cofactor.remove_column(j)
|
|
multiplier *= -1.0
|
|
determinant += multiplier * matrix.value(0, j) * determinant(cofactor)
|
|
|
|
return determinant
|
|
|
|
|
|
# Calculate the inverse of a Matrix
|
|
static func inverse(matrix: Matrix) -> Matrix:
|
|
var inverse: Matrix
|
|
|
|
# Minors and Cofactors
|
|
var minors_cofactors: Matrix = zeros(matrix.rows(), matrix.columns())
|
|
var multiplier: float = -1.0
|
|
|
|
for i in minors_cofactors.rows():
|
|
for j in minors_cofactors.columns():
|
|
var t_minor: Matrix = copy(matrix)
|
|
t_minor.remove_row(i)
|
|
t_minor.remove_column(j)
|
|
multiplier *= -1.0
|
|
minors_cofactors.set_value(multiplier * determinant(t_minor), i, j)
|
|
|
|
var transpose: Matrix = transpose(minors_cofactors)
|
|
var determinant: float = determinant(matrix)
|
|
|
|
inverse = multiply_float(transpose, 1 / determinant)
|
|
|
|
return inverse
|
|
|
|
# Transpose a given Matrix
|
|
static func transpose(_matrix : Matrix) -> Matrix:
|
|
var array : Array = []
|
|
array.resize(_matrix.get_size().y)
|
|
var row : Array = []
|
|
row.resize(_matrix.get_size().x)
|
|
for x in array.size():
|
|
array[x] = row.duplicate()
|
|
for i in range(_matrix.get_size().x):
|
|
for j in range(_matrix.get_size().y):
|
|
array[j][i] = (_matrix.to_array()[i][j])
|
|
return Matrix.new(array)
|
|
|
|
# Calculates the dot product (A*B) matrix between two Matrixes
|
|
static func dot(_matrix1 : Matrix, _matrix2 : Matrix) -> Matrix:
|
|
if _matrix1.get_size().y != _matrix2.get_size().x:
|
|
printerr("matrix1 number of columns: %s must be the same as matrix2 number of rows: %s"%[_matrix1.get_size().y, _matrix2.get_size().x])
|
|
return Matrix.new()
|
|
var array : Array = []
|
|
for x in range(_matrix1.get_size().x):
|
|
var row : Array = []
|
|
for y in range(_matrix2.get_size().y):
|
|
var sum : float
|
|
for k in range(_matrix1.get_size().y):
|
|
sum += (_matrix1.to_array()[x][k]*_matrix2.to_array()[k][y])
|
|
row.append(sum)
|
|
array.append(row)
|
|
return Matrix.new(array)
|
|
|
|
# Calculates the hadamard (element-wise product) between two Matrixes
|
|
static func hadamard(_matrix1 : Matrix, _matrix2 : Matrix) -> Matrix:
|
|
if _matrix1.get_size() != _matrix2.get_size():
|
|
printerr("matrix1 size: %s must be the same as matrix2 size: %s"%[_matrix1.get_size(), _matrix2.get_size()])
|
|
return Matrix.new()
|
|
var array : Array = []
|
|
for x in range(_matrix1.to_array().size()):
|
|
var row : Array = []
|
|
for y in range(_matrix1.to_array()[x].size()):
|
|
assert(typeof(_matrix1.to_array()[x][y]) != TYPE_STRING and typeof(_matrix2.to_array()[x][y]) != TYPE_STRING) #,"can't apply operations over a Matrix of Strings")
|
|
row.append(_matrix1.to_array()[x][y] * _matrix2.to_array()[x][y])
|
|
array.append(row)
|
|
return Matrix.new(array)
|
|
|
|
# Multiply a given Matrix for an int value
|
|
static func multiply_int(_matrix1 : Matrix, _int : int) -> Matrix:
|
|
var array : Array = _matrix1.to_array().duplicate()
|
|
for x in range(_matrix1.to_array().size()):
|
|
for y in range(_matrix1.to_array()[x].size()):
|
|
array[x][y]*=_int
|
|
array[x][y] = int(array[x][y])
|
|
return Matrix.new(array)
|
|
|
|
# Multiply a given Matrix for a float value
|
|
static func multiply_float(_matrix1 : Matrix, _float : float) -> Matrix:
|
|
var array : Array = _matrix1.to_array().duplicate()
|
|
for x in range(_matrix1.to_array().size()):
|
|
for y in range(_matrix1.to_array()[x].size()):
|
|
array[x][y]*=_float
|
|
return Matrix.new(array)
|
|
|
|
|
|
static func copy(matrix: Matrix) -> Matrix:
|
|
return Matrix.new(matrix.values.duplicate(true))
|
|
|
|
# ------------------------------------------------------------
|
|
static func get_letter_index(index : int) -> String:
|
|
return "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z".split(" ")[index]
|