diff --git a/src/main/java/com/mattrixwv/matrix/ModMatrix.java b/src/main/java/com/mattrixwv/matrix/ModMatrix.java new file mode 100644 index 0000000..5036a3e --- /dev/null +++ b/src/main/java/com/mattrixwv/matrix/ModMatrix.java @@ -0,0 +1,369 @@ +//Matrix/src/main/java/com/mattrixwv/matrix/ModMatrix.java +//Mattrixwv +// Created: 02-09-22 +//Modified: 02-09-22 +package com.mattrixwv.matrix; + + +import com.mattrixwv.matrix.exceptions.InvalidGeometryException; +import com.mattrixwv.matrix.exceptions.InvalidScalarException; + + +public class ModMatrix extends IntegerMatrix{ + protected int mod; + + //Helper functions + protected void setMod(int mod){ + if(mod <= 0){ + throw new InvalidScalarException("The mod must be > 0"); + } + + this.mod = mod; + } + protected int modValue(int value){ + int newValue = value % mod; + + if(newValue < 0){ + newValue += mod; + } + + return newValue; + } + protected int[] modValues(int[] values){ + int[] newValues = new int[values.length]; + + for(int cnt = 0;cnt < values.length;++cnt){ + newValues[cnt] = modValue(values[cnt]); + } + + return newValues; + } + protected void modGrid(){ + for(int row = 0;row < getNumRows();++row){ + for(int col = 0;col < getNumCols();++col){ + grid[row][col] = modValue(grid[row][col]); + } + } + } + @Override + protected void setGrid(int[][] grid){ + super.setGrid(grid); + modGrid(); + } + + //Constructors + public ModMatrix(int mod){ + super(); + setMod(mod); + modGrid(); + } + public ModMatrix(int[][] grid, int mod){ + super(); + setMod(mod); + setGrid(grid); + } + public ModMatrix(ModMatrix matrix){ + super(); + setMod(matrix.mod); + setGrid(matrix.grid); + } + public ModMatrix(IntegerMatrix matrix, int mod){ + super(); + setMod(mod); + setGrid(matrix.grid); + } + public ModMatrix(int rows, int cols, int fill, int mod){ + super(rows, cols, fill); + setMod(mod); + modGrid(); + } + + //Gets + public int getMod(){ + return mod; + } + @Override + public ModMatrix getRow(int row){ + return new ModMatrix(super.getRow(row), mod); + } + @Override + public ModMatrix getCol(int col){ + return new ModMatrix(super.getCol(col), mod); + } + //Sets + @Override + public void set(int row, int col, int value){ + super.set(row, col, modValue(value)); + } + @Override + public void setRow(int row, int[] elements){ + super.setRow(row, modValues(elements)); + } + @Override + public void setRow(int row, IntegerMatrix matrix){ + setRow(row, new ModMatrix(matrix, Integer.MAX_VALUE)); + } + public void setRow(int row, ModMatrix matrix){ + super.setRow(row, matrix); + modGrid(); + } + @Override + public void setCol(int col, int[] elements){ + super.setCol(col, elements); + modGrid(); + } + @Override + public void setCol(int col, IntegerMatrix matrix){ + setCol(col, new ModMatrix(matrix, Integer.MAX_VALUE)); + } + public void setCol(int col, ModMatrix matrix){ + super.setCol(col, matrix); + modGrid(); + } + //Adds + @Override + public void addRow(int[] elements){ + super.addRow(modValues(elements)); + } + @Override + public void addRow(IntegerMatrix matrix){ + addRow(new ModMatrix(matrix, Integer.MAX_VALUE)); + } + public void addRow(ModMatrix matrix){ + super.addRow(matrix); + modGrid(); + } + @Override + public void addCol(int[] elements){ + super.addCol(modValues(elements)); + } + @Override + public void addCol(IntegerMatrix matrix){ + addCol(new ModMatrix(matrix, Integer.MAX_VALUE)); + } + public void addCol(ModMatrix matrix){ + super.addCol(matrix); + modGrid(); + } + @Override + public ModMatrix appendRight(IntegerMatrix rightSide){ + return appendRight(new ModMatrix(rightSide, Integer.MAX_VALUE)); + } + public ModMatrix appendRight(ModMatrix rightSide){ + return new ModMatrix(super.appendRight(rightSide), mod); + } + @Override + public ModMatrix appendBottom(IntegerMatrix rightSide){ + return appendBottom(new ModMatrix(rightSide, Integer.MAX_VALUE)); + } + public ModMatrix appendBottom(ModMatrix rightSide){ + return new ModMatrix(super.appendBottom(rightSide), mod); + } + + //Simple operations + public static ModMatrix generateIdentity(int size){ + return generateIdentity(size, Integer.MAX_VALUE); + } + public static ModMatrix generateIdentity(int size, int mod){ + return new ModMatrix(IntegerMatrix.generateIdentity(size), mod); + } + @Override + public ModMatrix add(IntegerMatrix rightSide){ + return add(new ModMatrix(rightSide, Integer.MAX_VALUE)); + } + public ModMatrix add(ModMatrix rightSide){ + return new ModMatrix(super.add(rightSide), mod); + } + @Override + public ModMatrix add(int scalar){ + return new ModMatrix(super.add(scalar), mod); + } + @Override + public ModMatrix subtract(IntegerMatrix rightSide){ + return subtract(new ModMatrix(rightSide, Integer.MAX_VALUE)); + } + public ModMatrix subtract(ModMatrix rightSide){ + return new ModMatrix(super.subtract(rightSide), mod); + } + @Override + public ModMatrix subtract(int scalar){ + return new ModMatrix(super.subtract(scalar), mod); + } + @Override + public ModMatrix multiply(IntegerMatrix matrix){ + return multiply(new ModMatrix(matrix, Integer.MAX_VALUE)); + } + public ModMatrix multiply(ModMatrix matrix){ + return new ModMatrix(super.multiply(matrix), mod); + } + @Override + public ModMatrix multiply(int scalar){ + return new ModMatrix(super.multiply(scalar), mod); + } + @Override + public ModMatrix pow(int power){ + //Make sure the matrix is square so it can be multiplied + if(!isSquare()){ + throw new InvalidGeometryException("The matrix must be square to raise it to a power"); + } + //Make sure the power is positive + if(power < 0){ + throw new InvalidScalarException("The power must be >= 0"); + } + else if(power == 0){ + return new ModMatrix(getNumRows(), getNumCols(), 1, mod); + } + + //Create a new matrix for the product + ModMatrix newMatrix = clone(); + //Multiply the current grid power times + for(int currentPower = 1;currentPower < power;++currentPower){ + newMatrix = newMatrix.multiply(this); + } + + //Return the new grid + return newMatrix; + } + @Override + public int dotProduct(IntegerMatrix rightSide){ + return dotProduct(new ModMatrix(rightSide, Integer.MAX_VALUE)); + } + public int dotProduct(ModMatrix rightSide){ + return super.dotProduct(rightSide); + } + @Override + public ModMatrix hadamardProduct(IntegerMatrix rightSide){ + return hadamardProduct(new ModMatrix(rightSide, Integer.MAX_VALUE)); + } + public ModMatrix hadamardProduct(ModMatrix rightSide){ + return new ModMatrix(super.hadamardProduct(rightSide), mod); + } + + //Complex operations + @Override + public ModMatrix transpose(){ + return new ModMatrix(super.transpose(), mod); + } + @Override + public int det(){ + return determinant(); + } + @Override + public int determinant(){ + return super.determinant(); + } + @Override + public ModMatrix cof(){ + return cofactor(); + } + @Override + public ModMatrix cofactor(){ + //Make sure the matrix is square + if(!isSquare()){ + throw new InvalidGeometryException("A matrix must be square to find the cofactor matrix"); + } + + //Create a new grid + int[][] newGrid = new int[getNumRows()][getNumCols()]; + //If the grid is 1x1 return the grid + if(getNumRows() == 1){ + newGrid[0][0] = 1; + } + //Use the formula to find the cofactor matrix + else{ + for(int row = 0;row < getNumRows();++row){ + int multiplier = ((row % 2) == 0) ? 1 : -1; + for(int col = 0;col < getNumCols();++col){ + newGrid[row][col] = multiplier * laplaceExpansionHelper(row, col).determinant(); + multiplier = -multiplier; + } + } + } + + //Return the new matrix + return new ModMatrix(newGrid, mod); + } + @Override + public ModMatrix adj(){ + return adjoint(); + } + @Override + public ModMatrix adjoint(){ + return cofactor().transpose(); + } + @Override + public ModMatrix inverse(){ + //Make sure the matrix is square + if(!isSquare()){ + throw new InvalidGeometryException("A matrix must be square for it to have an inverse"); + } + + //Make sure the determinant is not 0 + int determinant = determinant(); + if(determinant == 0){ + throw new InvalidScalarException("The determinant cannot be 0"); + } + //Find the inverse of determinant % mod + int determinantInverse = -1; + for(int num = 1;num < mod;++num){ + if(modValue(determinant * num) == 1){ + determinantInverse = num; + break; + } + } + if(determinantInverse < 0){ + throw new InvalidScalarException("There is no inverse for the determinant"); + } + + //Find the matrix of cofactors and multiply the inverse determinant by cofactors and return + return adjoint().multiply(determinantInverse); + } + + //Object functions + @Override + public boolean equals(Object rightSide){ + if(rightSide.getClass().equals(this.getClass())){ + ModMatrix rightMatrix = (ModMatrix)rightSide; + + //Make sure they have the same number of elements + if(getNumRows() != rightMatrix.getNumRows()){ + return false; + } + else if(getNumCols() != rightMatrix.getNumCols()){ + return false; + } + + //Check every element + for(int row = 0;row < getNumRows();++row){ + for(int col = 0;col < getNumCols();++col){ + if(grid[row][col] != rightMatrix.grid[row][col]){ + return false; + } + } + } + + //If false hasn't been return yet then they are equal + return true; + } + else if(rightSide.getClass().equals(int[][].class)){ + int[][] rightMatrix = (int[][])rightSide; + + return equals(new ModMatrix(rightMatrix, mod)); + } + else{ + return false; + } + } + @Override + public int hashCode(){ + return grid.hashCode(); + } + @Override + public String toString(){ + return super.toString() + "\nmod(" + mod + ")"; + } + @Override + public ModMatrix clone(){ + return new ModMatrix(grid, mod); + } +}