Sep 19, 2008

Java :: Working with matrixes

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;
 }
 
}

No comments: