package jmathlib.core.tokens; import jmathlib.core.interpreter.*; import jmathlib.core.tokens.numbertokens.DoubleNumberToken; /**Class used to represent non numeric matrices*/ public class MatrixToken extends DataToken { /**The values of the matrix (array)*/ OperandToken value[][]; /** type of matrix */ private int typeOfMatrix; // 0 = numeric array // 1 = cell array /**Constructor taking the numbers value as a double @param _value = the values of the elements of the matrix*/ public MatrixToken(OperandToken[][] _value) { super(5, "matrix"); sizeY = _value.length; sizeX = _value[0].length; value = _value; } /**Constructor taking a DoubleNumberToken @param _value = the values of the elements of the matrix*/ public MatrixToken(DoubleNumberToken _value) { super(5, "matrix"); sizeY = _value.getSizeY(); sizeX = _value.getSizeX(); value = new OperandToken[sizeY][sizeX]; for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { value[yy][xx] = _value.getElement(yy, xx); } } } /**evaluate function - just returns the object itself @param operands = the matrices operands (not used) @return the matrix token itself*/ public OperandToken evaluate(Token[] operands, GlobalValues globals) { ErrorLogger.debugLine("Matrix evaluate size: "+sizeY+" "+sizeX); int sizeOfRowY = 0; // number or rows of each element in a row must be equal int sizeOfRowX = 0; // columns of each row int tmpSizeY = 0; // no. of rows of new overall matrix int tmpSizeX = 0; // no. or columns of new overall matrix boolean numberB = true; // stays true if array is purely numeric boolean stringB = true; // stays true if array is string and/or numeric /***** Evaluate every single element of the matrix *****/ /* Sub-matrices are possible, so row and column size may vary at first */ /* e.g. b=[1,2,a; */ /* 1,2,3,4,5] */ /* with a=[3,4,5] will result in b=[1,2,3,4,5; */ /* 1,2,3,4,5] */ for (int yy=0; yy<value.length; yy++) { for (int xx=0; xx<value[yy].length; xx++) { //if (value[yy][xx] != null) // maybe not necessary //{ value[yy][xx] = value[yy][xx].evaluate(null, globals); // Check if value[yy][xx] is array of number tokens // e.g.: [1,2,[3,4],5] if (value[yy][xx] instanceof DoubleNumberToken) { int valueSizeY = ((DoubleNumberToken)value[yy][xx]).getSizeY(); int valueSizeX = ((DoubleNumberToken)value[yy][xx]).getSizeX(); //ErrorLogger.debugLine("Matrix: eval: "+valueSizeY+" "+valueSizeX); // The number of rows of EACH element in a row must be equal // e.g. a=[1,b,3] must be a=[1, 2, 3, 4, 5, 3] // and not a=[1, [2,3]', 3] if (xx==0) { sizeOfRowY = valueSizeY; // rows of each element in THIS row tmpSizeY += valueSizeY; // compute total no. of rows sizeOfRowX = 0; // columns of THIS row } // Check if all elements in THIS row have the same number of rows if (valueSizeY != sizeOfRowY) Errors.throwMathLibException("Matrix: number of rows of each element must be equal"); // compute number of columns in THIS row sizeOfRowX += valueSizeX; } else if (value[yy][xx] instanceof CharToken) { if (xx==0) { sizeOfRowX = 0; } sizeOfRowX += 1; sizeOfRowY = 1; // at least one element is not a number numberB = false; } else { // at least one element is not a number numberB = false; // neither string nor number stringB = false; } //} } // end for xx // Store length of first row (as size for all rows) if (yy==0) { tmpSizeX = sizeOfRowX; // size of new overall matrix } // Check if all rows have the same number of columns if (sizeOfRowX != tmpSizeX) Errors.throwMathLibException("Matrix: number of columns of all rows must be equal"); } // end for yy // if isSymbolMode() and numberB=false // then return a MatrixToken with unresolved entries if ((!numberB) && (!stringB)) Errors.throwMathLibException("Matrix: is not numeric or string"); // e.g. ['asdf' 'asdf'] or // e.g. ['asdf' 55 99] if (stringB && !numberB) { ErrorLogger.debugLine("Matrix: found String"); if (tmpSizeY>1) Errors.throwMathLibException("Matrix: String with more than one line not implemented"); String retString = ""; // convert operands to a single string for (int x=0; x<tmpSizeX; x++) { if (value[0][x] instanceof CharToken) { retString += ((DataToken)value[0][x]).toString(); } else if (value[0][x] instanceof DoubleNumberToken) { // e.g. ['asdf' 65] -> 'asdfA' byte[] b = { new Double( ((DoubleNumberToken)value[0][x]).getValueRe() ).byteValue() }; try{ retString += new String(b, "UTF8"); } catch (Exception e) { Errors.throwMathLibException("Matrix: exception"); } } else Errors.throwMathLibException("Matrix: converting to string"); } return new CharToken(retString); } if (!numberB) return new MatrixToken(value); /******************** the matrix is purely NUMERIC *******************/ // create new array to store numeric data double valuesRe[][] = new double[tmpSizeY][tmpSizeX]; double valuesIm[][] = new double[tmpSizeY][tmpSizeX]; int valSizeY = 0; int valSizeX = 0; ErrorLogger.debugLine("Matrix: new bigger array "+tmpSizeY+" "+tmpSizeX); // fill new bigger array and expand sub matrices int yBig = 0; for (int yy=0; yy<value.length; yy++) { // number of rows of first element in row gives height of this line // e.g. a=[1,b,3] -> b must be 1*n matrix // e.g. a=[c,d] -> c and d have the same number of rows int xBig=0; for (int xx=0; xx<value[yy].length; xx++) { // get matrix of each element valSizeY = ((DoubleNumberToken)value[yy][xx]).getSizeY(); valSizeX = ((DoubleNumberToken)value[yy][xx]).getSizeX(); double[][] valRe = ((DoubleNumberToken)value[yy][xx]).getValuesRe(); double[][] valIm = ((DoubleNumberToken)value[yy][xx]).getValuesIm(); // copy small matrix of each element into global matrix for (int y=0; y<valSizeY; y++) { for (int x=0; x<valSizeX; x++) { valuesRe[yBig+y][xBig+x] = valRe[y][x]; valuesIm[yBig+y][xBig+x] = valIm[y][x]; } } xBig += valSizeX; } yBig += valSizeY; } return new DoubleNumberToken(valuesRe, valuesIm); } /**Convert the matrix to a string*/ public String toString() { String s = "["; int y = value.length; int x = value[0].length; //System.out.println("matrix toString "+y+" "+x); for (int yy=0; yy<y; yy++) { x = value[yy].length; for (int xx=0; xx<x; xx++) { if (value[yy][xx] != null) s = s + value[yy][xx].toString(); else s = s +" ---"; if (xx < (x-1)) { s = s + " , "; } } if (yy < (y-1)) { s = s + "],["; } } s = s + " ]"; return s; } /**Return the value of the number @return the value as an 2D array of double*/ public OperandToken[][] getValue() { ErrorLogger.debugLine("matrix getValue"); return value; } /**multiply arg by this object for a number token @param arg = the amount to multiply the matrix by @return the result as an OperandToken*/ /* public OperandToken multiply(OperandToken arg) { int y = value.length; int x = value[0].length; ErrorLogger.debugLine("matrix multiply dimension "+y+" "+x); // Multiply every single element of the matrix for (int yy=0; yy<y; yy++) { for (int xx=0; xx<x; xx++) { if (value[yy][xx] != null) { if (arg instanceof DoubleNumberToken) { System.out.println("Matrix multiply num"); value[yy][xx]=value[yy][xx].multiply(arg); } else if (arg instanceof VariableToken) { VariableToken argument = ((VariableToken)arg.clone()); ErrorLogger.debugLine("Matrix multiply variable "+value[yy][xx].toString()+" "+argument.toString()); value[yy][xx] = new Expression(new MulDivOperatorToken('*'), value[yy][xx], argument); ErrorLogger.debugLine("mt1"); //stefan value[yy][xx] = value[yy][xx].evaluate(null, globals); ErrorLogger.debugLine("mt2"); //value[yy][xx] = value[yy][xx].multiply(arg); ErrorLogger.debugLine("mt3"); //value[yy][xx] = arg.multiply(value[yy][xx]); ErrorLogger.debugLine("mmmmm1 "+value[yy][xx]+" "+argument); } else if (arg instanceof MatrixToken) { // Check dimensions (n,m) * (m,o) = (n,o) System.out.println("Matrix multiply not implemented"); } } } } MatrixToken retvalue = new MatrixToken(value); //retvalue = retvalue.evaluate(null); return retvalue; //stefan retvalue.evaluate(null, globals); } */ /**add arg to this object for a number token @param arg = the amount to add to the matrix @return the result as an OperandToken*/ /* public OperandToken add(OperandToken arg) { ErrorLogger.debugLine("matrix add"); //if(arg instanceof VariableToken) //return arg; // left argument int y1 = value.length; int x1 = value[0].length; // right argument OperandToken value2[][] = ((MatrixToken)arg).getValue(); int y2 = value2.length; int x2 = value2[0].length; if ( (y1 != y2) || (x1 != x2) ) return null; ErrorLogger.debugLine("matrix add ("+y1+","+x1+")-("+y2+","+x2+")" ); for (int yy=0; yy<y1; yy++) { for (int xx=0; xx<x1; xx++) { OperandToken left = value[yy][xx]; OperandToken right = value2[yy][xx]; if ( (left instanceof DoubleNumberToken) && (right instanceof DoubleNumberToken) ) { value[yy][xx]=left.add(right); ErrorLogger.debugLine("Matrix add Number Number"); } else { // build expression and evaluate expression ErrorLogger.debugLine("Matrix add Expressions"); value[yy][xx] = new Expression(new AddSubOperatorToken('+'), left, right); //stefam value[yy][xx] = value[yy][xx].evaluate(null, globals); } ErrorLogger.debugLine("Matrix add to String "+value[yy][xx].toString()); } } return new MatrixToken(value); } */ public OperandToken elementAt(int y, int x) { return value[y][x]; } } // end MatrixToken