github.com/djordje200179/extendedlibrary/datastructures@v1.7.1-0.20240227175559-d09520a92dd4/other/matrix/matrix.go (about) 1 package matrix 2 3 import "fmt" 4 5 // Matrix is a two-dimensional array of values. 6 // The zero value is ready to use. Do not copy a non-zero Matrix. 7 type Matrix[T any] struct { 8 values []T 9 10 columns int 11 } 12 13 // New creates a new matrix with the given size. 14 func New[T any](size Size) *Matrix[T] { 15 values := make([]T, size.Elements()) 16 17 matrix := &Matrix[T]{ 18 values: values, 19 columns: size.Width, 20 } 21 22 return matrix 23 } 24 25 // NewFromSlices creates a new matrix from the given slices. 26 func NewFromSlices[T any](values [][]T) *Matrix[T] { 27 if len(values) == 0 { 28 return New[T](Size{}) 29 } 30 31 rows := len(values) 32 columns := len(values[0]) 33 34 for _, row := range values { 35 if len(row) != columns { 36 panic("Matrix rows have different lengths") 37 } 38 } 39 40 matrix := New[T](Size{rows, columns}) 41 42 for i, row := range values { 43 for j, value := range row { 44 matrix.Set(i, j, value) 45 } 46 } 47 48 return matrix 49 } 50 51 // Size returns the size of the matrix. 52 func (matrix *Matrix[T]) Size() Size { 53 var rows int 54 if matrix.columns != 0 { 55 rows = len(matrix.values) / matrix.columns 56 } 57 58 return Size{rows, matrix.columns} 59 } 60 61 // GetRef returns a reference to the value at the given position. 62 func (matrix *Matrix[T]) GetRef(row, column int) *T { 63 index := matrix.Size().Index(row, column) 64 return &matrix.values[index] 65 } 66 67 // Get returns the value at the given position. 68 func (matrix *Matrix[T]) Get(row, column int) T { 69 return *matrix.GetRef(row, column) 70 } 71 72 // Set sets the value at the given position. 73 func (matrix *Matrix[T]) Set(row, column int, value T) { 74 *matrix.GetRef(row, column) = value 75 } 76 77 // Clone returns a copy of the matrix. 78 func (matrix *Matrix[T]) Clone() *Matrix[T] { 79 newMatrix := New[T](matrix.Size()) 80 copy(newMatrix.values, matrix.values) 81 82 return newMatrix 83 } 84 85 // InsertRow inserts a row at the given index. 86 func (matrix *Matrix[T]) InsertRow(index int, row []T) { 87 if len(row) != matrix.columns { 88 panic("Row length does not match matrix width") 89 } 90 91 newValues := make([]T, len(matrix.values)+matrix.columns) 92 93 oldPrevPart := matrix.values[:index*matrix.columns] 94 newPrevPart := newValues[:index*matrix.columns] 95 copy(newPrevPart, oldPrevPart) 96 97 oldNextPart := matrix.values[index*matrix.columns:] 98 newNextPart := newValues[(index+1)*matrix.columns:] 99 copy(newNextPart, oldNextPart) 100 101 newPart := newValues[index*matrix.columns : (index+1)*matrix.columns] 102 copy(newPart, row) 103 104 matrix.values = newValues 105 } 106 107 // InsertColumn inserts a column at the given index. 108 func (matrix *Matrix[T]) InsertColumn(index int, column []T) { 109 size := matrix.Size() 110 111 if len(column) != size.Height { 112 panic("Column length does not match matrix height") 113 } 114 115 newValues := make([]T, len(matrix.values)+size.Height) 116 117 for i := size.Height - 1; i >= 0; i-- { 118 oldRow := matrix.values[i*size.Width : (i+1)*size.Width] 119 newRow := newValues[i*(size.Width+1) : (i+1)*(size.Width+1)] 120 121 copy(newRow[:index], oldRow[:index]) 122 copy(newRow[index+1:], oldRow[index:]) 123 newRow[index] = column[i] 124 } 125 126 matrix.values = newValues 127 matrix.columns++ 128 } 129 130 // AppendRow appends a row to the matrix. 131 func (matrix *Matrix[T]) AppendRow(row []T) { 132 if len(row) != matrix.columns { 133 panic("Row length does not match matrix width") 134 } 135 136 matrix.values = append(matrix.values, row...) 137 } 138 139 // AppendColumn appends a column to the matrix. 140 func (matrix *Matrix[T]) AppendColumn(column []T) { 141 matrix.InsertColumn(matrix.columns, column) 142 } 143 144 // RemoveRow removes the row at the given index. 145 func (matrix *Matrix[T]) RemoveRow(index int) { 146 newValues := make([]T, len(matrix.values)-matrix.columns) 147 148 oldPrevPart := matrix.values[:index*matrix.columns] 149 newPrevPart := newValues[:index*matrix.columns] 150 copy(newPrevPart, oldPrevPart) 151 152 oldNextPart := matrix.values[(index+1)*matrix.columns:] 153 newNextPart := newValues[index*matrix.columns:] 154 copy(newNextPart, oldNextPart) 155 156 matrix.values = newValues 157 } 158 159 // RemoveColumn removes the column at the given index. 160 func (matrix *Matrix[T]) RemoveColumn(index int) { 161 size := matrix.Size() 162 163 newValues := make([]T, len(matrix.values)-size.Height) 164 165 for i := range size.Height { 166 oldRow := matrix.values[i*(size.Width+1) : (i+1)*(size.Width+1)] 167 newRow := newValues[i*size.Width : (i+1)*size.Width] 168 169 copy(newRow[:index], oldRow[:index]) 170 copy(newRow[index:], oldRow[index+1:]) 171 } 172 173 matrix.values = newValues 174 matrix.columns-- 175 } 176 177 // Reshape reshapes the matrix into the given size. 178 // The number of elements must be the same. 179 // The matrix is reshaped in row-major order. 180 func (matrix *Matrix[T]) Reshape(newSize Size) { 181 oldSize := matrix.Size() 182 183 if oldSize.Elements() != newSize.Elements() { 184 panic(fmt.Sprintf("Can't reshape matrix into %s", newSize)) 185 } 186 187 matrix.columns = newSize.Width 188 } 189 190 // Transpose transposes the matrix. 191 func (matrix *Matrix[T]) Transpose() { 192 oldSize := matrix.Size() 193 newSize := oldSize.Transposed() 194 195 newValues := make([]T, newSize.Elements()) 196 197 for i := range newSize.Height { 198 for j := range newSize.Width { 199 newIndex := newSize.Index(i, j) 200 oldIndex := oldSize.Index(j, i) 201 202 newValues[newIndex] = matrix.values[oldIndex] 203 } 204 } 205 206 matrix.values = newValues 207 matrix.columns = newSize.Width 208 }