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  }