I had an assignment in college to build a Java program that would calculate matrix expressions. Examples for this were:
Expression: A = [ [ 1 2 ] [ 3 4 ] ]
saves matrix
1 2
3 4
to variable A.
Expression: B = A * A
calculates the matrix A*A and saves the result in variable B
Expression: B - [ [ 9 8 ] [ 7 6 ] ]
calculates matrix B - matrix
9 8
7 6
and prints the result
Here's the class:
import java.util.*;
import java.io.*;
public class Matrike {
//v hashmap se bodo shranjevale spremenljivke in njihove vrednosti
static Map<String,String> vars = new HashMap<String,String>();
static boolean debug=false; //param debug za podrobnejsi izpis
static boolean gotSyntaxError; //ne izpisi rezultata, ce je napaka
/****************************************************************************************
M A I N (done)
****************************************************************************************/
public static void main(String[] args) {
String niz = null;
boolean ok=false;
if(args.length>0)debug=args[0].equals("debug"); //debug=true/false
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
do {
System.out.printf(": ");
ok = false;
try {
niz = br.readLine();
ok = true;
}
catch(IOException ioe) {
System.out.printf("! Input error\n");
ok = false;
}
if(ok && niz.length() > 0) {
analiza(niz); //ce je vse ok in ni prazn string, zacni procesirat
}
}
while (!niz.equals("exit")); //exit = komanda za izhod
System.out.println("* Bye");
}
/****************************************************************************************
P R O C E S I R A N J E K O M A N D E (done)
****************************************************************************************/
//analiza inputa - shrani spremenljivke, poslje izraz v funkcijo za racunanje
public static void analiza(String niz) {
StringBuffer varBuffer = new StringBuffer();
StringBuffer valBuffer = new StringBuffer();
String val=null; //desna stran enacaja
String var=null; //spremenljivka
gotSyntaxError=false;
/////////////////////////////////////////////////////////////////////////////////////////
//[komande] izpisi vse spremenljivke
if(niz.equals("vars")||niz.equals("var")||niz.equals("variables")){
printVars();
return;
}
if(niz.equals("clean")||niz.equals("clear")){
vars.clear();
System.out.println("* Cleaning up variables");
return;
}
/////////////////////////////////////////////////////////////////////////////////////////
//iskanje negativnih stevil, da se ne bo mesalo z operatorjem minus
boolean foundOklepaj=false;
StringBuffer nizReplace = new StringBuffer();
for(int i=0;i<niz.length();i++) {
if(niz.charAt(i)=='[')foundOklepaj=true; //ce je negativna cifra znotraj matrike
if(niz.charAt(i)==']')foundOklepaj=false;
if((niz.charAt(i)=='-')&&foundOklepaj) {
nizReplace.append('_'); //bo znak za minus zamenjalo s _
} else {
nizReplace.append(niz.charAt(i));
}
}
niz=nizReplace.toString();
/////////////////////////////////////////////////////////////////////////////////////////
//shrani izraz za racunanje, ce je najden enacaj je ta za enacajem
int eqLoc=0;
for(int i=0;i<niz.length();i++)if(niz.charAt(i)=='=')eqLoc=i+1; //+1, enacaja ne shrani
for(int i=eqLoc;i<niz.length();i++)valBuffer.append(niz.charAt(i));
val=valBuffer.toString();
/////////////////////////////////////////////////////////////////////////////////////////
//ce so v izrazu operatorji, je treba izraz poracunat in popravit spremenjivko val
int nOperations=0;
for(int i=0;i<niz.length();i++)
if(niz.charAt(i)=='+'||niz.charAt(i)=='*'||niz.charAt(i)=='-')
nOperations++;
if(nOperations>0) { //ali je treba racunat?
///////POSLJI V KALKULATOR
val = calcMatrix(val,nOperations); //treba je racunat, calcMatrix bo vrnila nov rezultat
///////----------
if((val != null) && (!gotSyntaxError)) { //izpise pa ga tule, ne calcMatrix, pa izpisi ce ni kasn error
if(isScalar(val)) { //ce je matrika enodimenzionalna, je skalar - pretvori
StringBuffer toScalar = new StringBuffer();
for(int i=0;i<val.length();i++)
if( (val.charAt(i)!=' ') && (val.charAt(i)!='[') && (val.charAt(i)!=']') )
toScalar.append(val.charAt(i));
val=toScalar.toString();
}
//TUKAJ JE GLAVNI IZPIS REZULTATA !!!
System.out.printf("> %s\n",val);
//----
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//shrani spremenljivke
for(int i=0;i<niz.length();i++) {
if(niz.charAt(i)=='=') {
for(int j=0;j<i;j++)varBuffer.append(niz.charAt(j));
var=varBuffer.toString();
vars.put(var.replaceAll(" ",""),val);
}
}
}
/****************************************************************************************
R A C U N A N J E I Z R A Z A M A T R I K (done)
****************************************************************************************/
public static String calcMatrix(String matrix,int nOperations) {
/*
kalkulator deluje na isti princip kot racuni.c - naredi dve tabeli:
- tabela operandov
- tabela operatorjev
Nato se sprehajamo po tabeli operatorjev po prioriteti in racunamo po dva elementa hkrati.
Rezultat napisemo v indeks prvega elementa, drugi element zbrisemo in zmanjsamo tabelo za 1 in
pomaknemo v levo.
Tabela je tridimenzionalna - prvi indeks je indeks operandov, druga dva indeksa sta 2D tabela matrike
*/
int[][][] izraz = new int[nOperations+1][][];
char[] operatorji = new char[nOperations];
String result=null;
int a=0;
//shrani operatorje
for(int i=0;i<matrix.length();i++)
if(matrix.charAt(i)=='+'||matrix.charAt(i)=='*'||matrix.charAt(i)=='-') {
operatorji[a]=matrix.charAt(i);
a++;
}
//shrani operande (matrike) v tabelo
a=0;
String tmp=null;
//StringTokenizer st = new StringTokenizer(matrix,"+-*"); //razbij po operatorjih
String tokens[] = matrix.split("\\+|\\-|\\*");
//while (st.hasMoreTokens()) {
for(int i=0;i<tokens.length;i++) {
//tmp=st.nextToken();
tmp=tokens[i];
//poglej ce je tmp spremenljivka in jo zamenjaj z matriko
tmp=varToMatrix(tmp);
//poglej ce je tmp skalar in ga zamenjaj v 1x1 matriko ;-)
if(isNumber(tmp)) {
tmp=tmp.replaceAll(" ","");
StringBuffer skalar = new StringBuffer();
skalar.append("[[");
try {
skalar.append(Integer.parseInt(tmp));
}
catch(NumberFormatException e) {
System.out.printf("! Syntax error: scalar is not a number\n");
gotSyntaxError=true;
return null;
}
skalar.append("]]");
tmp=skalar.toString();
}
/*Y**************************************************************************************/
//poracunaj dimenzije tabele
int y=getMatrixDimensionY(tmp);
/*X*************************************************************************************/
int x=getMatrixDimensionX(tmp);
/***************************************************************************************/
int counter=0; //to je sam za cekiranje
try {
//StringTokenizer stCount = new StringTokenizer(tmp," ][");
String numberTokens[]=tmp.split(" |\\[|\\]");
//while(stCount.hasMoreTokens()){
for(int w=0;w<numberTokens.length;w++) {
if((numberTokens[w]!=null) && (!numberTokens[w].equals(""))) counter++;
//stCount.nextToken();
}
}
catch(NullPointerException e) {
System.out.println("! Syntax error: empty variable, clean up with 'vars'");
gotSyntaxError=true;
return null;
}
if(debug)System.out.printf("calcMatrix? x=%d,y=%d\n",x,y);
/***************************************************************************************/
//ce je x ali y negativen, ali nista kolicnika je struktura matrike nepravilna
if(x==0||y==0) {
System.out.printf("! Syntax error: no numbers in the matrix\n");
gotSyntaxError=true;
return null;
}
if(x<0||y<0||counter%y!=0){
System.out.printf("! Syntax error: invalid matrix dimension\n");
gotSyntaxError=true;
return null;
}
if((x>1)&&(counter%x!=0)) {
System.out.printf("! Syntax error: missing number in the matrix\n");
gotSyntaxError=true;
return null;
}
//pretvori string v tabelo integerjev
izraz[a] = new int[x][y];
izraz[a]=matrixToTable(tmp,x,y);
a++;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//TABELA JE SHRANJENA, zacni racunat
int lenOperatorji=operatorji.length;
int lenIzraz=izraz.length;
String rezultat=null;
/***** ISCI OPERATORJE IN POPRAVLJAJ TABELO ! *****/
for(int op=1;op<4;op++) {
char f;
switch(op) {
default:
case 1:f='*'; break;
case 2:f='-'; break;
case 3:f='+'; break;
}
int stejop=0;
for(int i=0;i<lenOperatorji;i++)
if(operatorji[i]==f)stejop++;
while(stejop>0) {
for(int i=0;i<lenOperatorji;i++) { //break =>
if(operatorji[i]==f) {
if((isScalar(tableToMatrix(izraz[i])) || isScalar(tableToMatrix(izraz[i+1]))) && (f=='*')) { //ali je operacija s skalarjem
//pozor: ta funkcija je definirana samo za mnozenje s skalarjem (ali ce sta oba skalarja), v drugem primeru se bo obravnavalo kot operacijo med dvema matrikama
rezultat=doMatrixMath(izraz[i],izraz[i+1],'s');
int x=getMatrixDimensionX(rezultat);
int y=getMatrixDimensionY(rezultat);
if(x>0||y>0)
izraz[i]=matrixToTable(rezultat,x,y);
if(debug)System.out.printf("calcMatrix/ (Scalar) Set %s\n",rezultat);
} else { //drugace...
rezultat=doMatrixMath(izraz[i],izraz[i+1],f);
if(debug)System.out.printf("calcMatrix/ Got %c\n",f);
int x=getMatrixDimensionX(rezultat);
int y=getMatrixDimensionY(rezultat);
if(x>0||y>0)
izraz[i]=matrixToTable(rezultat,x,y);
if(debug)System.out.printf("calcMatrix/ Set %s\n",rezultat);
}
////////////Popravi tabelo
for(int j=i;j<lenOperatorji;j++)
if(j+1<lenOperatorji)operatorji[j]=operatorji[j+1]; //kle!
lenOperatorji--;
//se operande
for(int j=i+1;j<lenIzraz;j++)
if(j+1<lenIzraz)izraz[j]=izraz[j+1];
lenIzraz--;
////////ok
stejop--;
break; // <= break
}
}
}
}
result=tableToMatrix(izraz[0]);
if(debug)System.out.printf("calcMatrix$ %s\n",result);
return result;
}
/****************************************************************************************
METODA ZA DIMENZIJE MATRIKE ZA 2D TABELO (done)
****************************************************************************************/
public static int getMatrixDimensionX(String matrix) {
int f=-1,g=-1,x=-1;
if(matrix!=null) {
for(int i=0;i<matrix.length();i++)if(matrix.charAt(i)=='[')f++;
//x dimenzija tabele = N("[")-1
for(int i=0;i<matrix.length();i++)if(matrix.charAt(i)==']')g++;
if(g==f)x=g;
}
return x;
}
public static int getMatrixDimensionY(String matrix) {
int y=-1;
int counter=0;
if(matrix==null||matrix.equals("")||matrix.equals(null)) {
if(debug)System.out.println("! Syntax error: null parameter (getMatrixDimension)");
gotSyntaxError=true;
return -1;
}
String tmp=matrix;
if(tmp==null||tmp.equals("")||tmp.equals(null)) {
if(debug)System.out.println("! Syntax error: null parameter (getMatrixDimensionY)");
gotSyntaxError=true;
return -1;
}
if(debug)System.out.printf("getMatrixDimensionY# %s\n",tmp);
if(tmp!=null) {
if(debug)System.out.printf("getMatrixDimensionY# Tokenizing ...\n");
//StringTokenizer stCount = new StringTokenizer(tmp," ][");
String numberTokens[]=tmp.split(" |\\[|\\]");
//while(stCount.hasMoreTokens()){
for(int w=0;w<numberTokens.length;w++) {
if((numberTokens[w]!=null) && (!numberTokens[w].equals(""))) counter++;
//stCount.nextToken();
}
}
y=counter/getMatrixDimensionX(tmp);
//y dimenzija tabele = N(stevilk)/x
return y;
}
/****************************************************************************************
METODA ZA RACUNANJE DVEH MATRIK
****************************************************************************************/
public static String doMatrixMath(int[][] p1,int[][] p2,char f) {
String result=null;
if(p1==null||p2==null) {
System.out.println("! Syntax error: parameter missing, nothing to do");
gotSyntaxError=true;
return null;
}
int x1=p1.length;
int x2=p2.length;
int y1=p1[0].length;
int y2=p2[0].length;
switch(f) {
// MNOZENJE S SKALARJEM
case 's':
int scalar=0;
result=tableToMatrix(p1);
if(isScalar(tableToMatrix(p1))) {
scalar=p1[0][0]; //doloci skalar
for(int i=0;i<p2.length;i++)
for(int j=0;j<p2[i].length;j++)
p2[i][j]*=scalar; //in pomnozi s drugim parametrom
result=tableToMatrix(p2);
} else { //ravno obratno
scalar=p2[0][0];
for(int i=0;i<p1.length;i++)
for(int j=0;j<p1[i].length;j++)
p1[i][j]*=scalar;
result=tableToMatrix(p1);
}
break;
// PLUS in MINUS
case '+':
case '-':
//vsota in razlika matrik je definirana samo za matrike enakih dimenzij
//vir: http://en.wikipedia.org/wiki/Matrix_%28mathematics%29#Sum
if(x1!=x2||y1!=y2) {
System.out.println("! Syntax error: matrices do not have the same dimension");
gotSyntaxError=true;
return null;
}
for(int x=0;x<x1;x++) {
for(int y=0;y<y1;y++) {
switch(f) {
default:
case '+': p1[x][y]+=p2[x][y]; break;
case '-': p1[x][y]-=p2[x][y]; break;
}
}
}
result=tableToMatrix(p1);
break;
//KRAT
case '*':
default:
//mnozenje matrik je definirano za matrike, katere stevilo stolpcev ene matrike je enako stevilu vrstic druge
//vir: http://en.wikipedia.org/wiki/Matrix_multiplication#Ordinary_matrix_product
int dx=0; //x dimenzija matrike produkta
int dy=0; //y dimenzija matrike produkta
int max=0; //sirsa dimenzija
if(x1>=x2) { //p1 je daljsi v stolpcih ali pa sta p1 in p2 kvadrat
dx=x2;
dy=y1;
max=x1;
} else { //p2 je daljsi v stolpcih
dx=x1;
dy=y2;
max=x2;
}
if(debug)System.out.printf("doMatrixMath: %d %d %d %d\n",x1,y2,x2,y1);
if((x1!=x2||y1!=y2)&&(x1!=y2||x2!=y1)) {
System.out.println("! Syntax error: matrices do not have the opposite or same dimension");
gotSyntaxError=true;
return null;
}
if(debug)System.out.printf("doMatrixMath-Multiplication:\ndx = %d\ndy = %d\nmax = %d\n",dx,dy,max);
int[][] p = new int[dx][dy]; //dimenzije matrike produkta
for(int xp=0;xp<dx;xp++) {
for(int yp=0;yp<dy;yp++) {
p[xp][yp]=0;
for(int x=0;x<max;x++) {
if(debug)System.out.printf("p[%d][%d] += p1[%d][%d](%d) * p2[%d][%d](%d)\n",
xp,yp,xp,x,p1[xp][x],x,yp,p2[x][yp]);
if(x1>=x2) p[xp][yp]+=p2[xp][x]*p1[x][yp];
else p[xp][yp]+=p1[xp][x]*p2[x][yp];
}
}
}
result=tableToMatrix(p);
break;
}
return result;
}
/****************************************************************************************
PRETVORBA MATRIKE IZ STRING V 2D TABELO INTEGER (done)
****************************************************************************************/
public static int[][] matrixToTable(String matrix,int x,int y) {
int[][] result = new int[x][y];
int[] nums = new int[x*y];
//shrani stevilke v 1D tabelo
int counter=0;
//StringTokenizer st = new StringTokenizer(matrix," ][");
String tokens[]=matrix.split(" |\\[|\\]");
//while (st.hasMoreTokens()) {
for(int w=0;w<tokens.length;w++) {
try {
//String tmp=st.nextToken();
////////
String tmp = tokens[w];
if((tokens[w]==null) || (tokens[w].equals(""))) continue;
///////
tmp=tmp.replaceAll("_","-");
try {
nums[counter]=Integer.parseInt(tmp);
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.printf("! Syntax error: unknown matrix array error\n");
gotSyntaxError=true;
return null;
}
if(debug)System.out.printf("matrixToTable+ %d\n",nums[counter]);
counter++;
}
catch(NumberFormatException nfe) {
System.out.printf("! Syntax error: element in matrix is not a number\n");
gotSyntaxError=true;
//not a number
return null;
}
}
//zapis v 2D tabelo
counter=0;
for(int i=0;i<x;i++) {
for(int j=0;j<y;j++) {
result[i][j]=nums[counter];
if(debug)System.out.printf("matrixToTable- {%d,%d} %d\n",i,j,nums[counter]);
counter++;
}
}
//vrni rezultat
if(debug)System.out.printf("matrixToTable@ %s\n",tableToMatrix(result));
return result;
}
/****************************************************************************************
PRETVORBA 2D TABELE V STRING MATRIKE ([[1 2][3 4]]) (done)
****************************************************************************************/
public static String tableToMatrix(int[][] tab) {
StringBuffer matrix = new StringBuffer();
String result=null;
if(tab==null) {
if(debug)System.out.println("! Syntax error: null parameter (tableToMatrix)");
gotSyntaxError=true;
return null;
}
matrix.append("[ ");
for(int x=0;x<tab.length;x++) {
matrix.append("[ ");
for(int y=0;y<tab[x].length;y++) {
matrix.append(tab[x][y]+" ");
}
matrix.append("] ");
}
matrix.append("]");
//Lep izpis, primer: [ [ 2 3 ] [ 4 5 ] ]
result=matrix.toString();
if(debug)System.out.printf("tableToMatrix: %s\n",result);
return result;
}
/****************************************************************************************
IZPIS SPREMENLJIVK(done)
****************************************************************************************/
public static void printVars() {
Set set = vars.entrySet();
List<String> clean = new ArrayList<String>();
Iterator i = set.iterator();
String var,val;
System.out.println("* Listing variables");
while(i.hasNext()) { //sprehodi se po mapSetu
Map.Entry entry = (Map.Entry) i.next();
var = (String) entry.getKey();
val = (String) entry.getValue();
try {
val = val.replaceAll("_","-"); //zajebi cel svet in izpisi pravilne minuse
System.out.printf("# %s = %s\n",var,val);
}
catch(NullPointerException e) {
System.out.printf("! Empty variable '%s' removed\n",var);
clean.add(var); /* shrani seznam spremenljivk za izbris */
}
}
/* pocisti prazne sprmenljivke */
Iterator j=clean.iterator();
while(j.hasNext())vars.remove(j.next());
/* konec */
System.out.println("* End of list");
}
/****************************************************************************************
VRACANJE VREDNOSTI SPREMENLJIVKE (done)
****************************************************************************************/
public static String varToMatrix(String tmp) {
String result = tmp; //ce spremenljivka ne obstaja, vrni isti string
StringBuffer buffer = new StringBuffer();
for(int i=0;i<tmp.length();i++)
if(tmp.charAt(i)!=' ')
buffer.append(tmp.charAt(i));
String chkEq = buffer.toString(); //v chkEq se nahaja spremenljivka
if(debug)System.out.printf("varToMatrix# chkEq(%s)\n",chkEq);
Set set = vars.entrySet();
Iterator i = set.iterator();
String var,val;
while(i.hasNext()) {
Map.Entry entry = (Map.Entry) i.next();
var = (String) entry.getKey();
val = (String) entry.getValue();
if(var.equals(chkEq)) result=val;
}
if(debug)System.out.printf("varToMatrix# %s\n",result);
return result;
}
/****************************************************************************************
METODA ZA PREVERJANJE CE JE PARAMETER STEVILKA (done)
****************************************************************************************/
public static boolean isNumber(String tmp) {
boolean result = false;
if(tmp!=null)tmp=tmp.replaceAll(" ","");
else return false;
try {
Integer.parseInt(tmp);
result = true;
}
catch(NumberFormatException nfe) {}
return result;
}
/****************************************************************************************
METODA ZA PREVERJANJE CE JE MATRIKA 1d - SKALAR (done)
****************************************************************************************/
public static boolean isScalar(String tmp) {
boolean result=false;
if((getMatrixDimensionX(tmp)==1) && (getMatrixDimensionY(tmp)==1))
result=true;
return result;
}
}