//Matrix/src/main/java/com/mattrixwv/matrix/ModMatrix.java //Mattrixwv // Created: 02-09-22 //Modified: 07-01-22 package com.mattrixwv.matrix; import java.util.Arrays; 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){ if(values == null){ throw new InvalidGeometryException("Array cannot be null"); } 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 = new ModMatrix(this); //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 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 == null){ return false; } else if(rightSide.getClass().equals(this.getClass())){ return equals((ModMatrix)rightSide); } else if(rightSide.getClass().equals(int[][].class)){ int[][] rightMatrix = (int[][])rightSide; return equals(new ModMatrix(rightMatrix, mod)); } else{ return false; } } public boolean equals(ModMatrix rightMatrix){ //Make sure they have the same number of elements if((getNumRows() != rightMatrix.getNumRows()) || (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; } @Override public int hashCode(){ return Arrays.hashCode(grid); } @Override public String toString(){ return super.toString() + "\nmod(" + mod + ")"; } }