From 006fa4de7fdd87ee2c805e6a8cb2fc5369618b1f Mon Sep 17 00:00:00 2001 From: fenix-hub Date: Sun, 15 Jan 2023 23:21:25 +0100 Subject: [PATCH] add matrix methods --- .../utilities/classes/structures/matrix.gd | 77 ++++++++++++++++++- .../classes/structures/matrix_generator.gd | 62 +++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/addons/easy_charts/utilities/classes/structures/matrix.gd b/addons/easy_charts/utilities/classes/structures/matrix.gd index f58ae4a..7a3bf17 100644 --- a/addons/easy_charts/utilities/classes/structures/matrix.gd +++ b/addons/easy_charts/utilities/classes/structures/matrix.gd @@ -16,6 +16,10 @@ func update_row(row : Array, index : int) -> void: assert(rows() > index, "the row size must match matrix row size") values[index] = row +func remove_row(index: int) -> void: + assert(rows() > index, "the row size must match matrix row size") + values.remove(index) + func insert_column(column : Array, index : int = values[0].size()) -> void: if columns() != 0: assert(column.size() == rows(), "the column size must match matrix column size") @@ -27,6 +31,11 @@ func update_column(column : Array, index : int) -> void: for row_idx in column.size(): values[row_idx][index] = column[row_idx] +func remove_column(index: int) -> void: + assert(columns() > index, "the column index must be at least equals to the rows count") + for row in get_rows(): + row.remove(index) + func resize(rows: int, columns: int) -> void: for row in range(rows): var row_column: Array = [] @@ -45,6 +54,12 @@ func rows() -> int: func columns() -> int: return values[0].size() if rows() != 0 else 0 +func value(row: int, column: int) -> float: + return values[row][column] + +func set_value(value: float, row: int, column: int) -> void: + values[row][column] = value + func get_column(column : int) -> Array: assert(column < columns(), "index of the column requested (%s) exceedes matrix columns (%s)"%[column, columns()]) var column_array : Array = [] @@ -67,9 +82,64 @@ func get_rows(from : int = 0, to : int = rows()-1) -> Array: return values.slice(from, to) # return MatrixGenerator.from_array(values) -func empty() -> bool: +func is_empty() -> bool: return rows() == 0 and columns() == 0 + +func is_square() -> bool: + return columns() == rows() + + +func is_diagonal() -> bool: + if not is_square(): + return false + + for i in rows(): + for j in columns(): + if i != j and values[i][j] != 0: + return false + + return true + + +func is_upper_triangular() -> bool: + if not is_square(): + return false + + for i in rows(): + for j in columns(): + if i > j and values[i][j] != 0: + return false + + return true + + +func is_lower_triangular() -> bool: + if not is_square(): + return false + + for i in rows(): + for j in columns(): + if i < j and values[i][j] != 0: + return false + + return true + + +func is_triangular() -> bool: + return is_upper_triangular() or is_lower_triangular() + + +func is_identity() -> bool: + if not is_diagonal(): + return false + + for i in rows(): + if values[i][i] != 1: + return false + + return true + func _to_string() -> String: var last_string_len : int for row in values: @@ -83,6 +153,11 @@ func _to_string() -> String: string+="\n" return string +# ---- +func set(position: String, value) -> void: + var t_pos: Array = position.split(",") + values[t_pos[0]][t_pos[1]] = value + # -------------- func _get(_property : String): # ":" --> Columns diff --git a/addons/easy_charts/utilities/classes/structures/matrix_generator.gd b/addons/easy_charts/utilities/classes/structures/matrix_generator.gd index c8cd0c0..f86805a 100644 --- a/addons/easy_charts/utilities/classes/structures/matrix_generator.gd +++ b/addons/easy_charts/utilities/classes/structures/matrix_generator.gd @@ -2,6 +2,15 @@ tool extends Reference 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) @@ -33,6 +42,55 @@ static func sub_matrix(_matrix : Matrix, from : PoolIntArray, to : PoolIntArray) 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 = [] @@ -93,6 +151,10 @@ static func multiply_float(_matrix1 : Matrix, _float : float) -> Matrix: 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]