/* * This file is part or JMathLib * * Check it out at http://www.jmathlib.de * * Author: * (c) 2005-2009 */ package jmathlib.core.tokens.numbertokens; import jmathlib.core.interpreter.ErrorLogger; import jmathlib.core.interpreter.Errors; import jmathlib.core.tokens.DataToken; import jmathlib.core.tokens.NumberToken; import jmathlib.core.tokens.CharToken; import jmathlib.core.tokens.OperandToken; public class DoubleNumberToken extends NumberToken { /**Complex values of the token * the data is organizes as on single vector. * e.g. a=[1,2;3,4] will be stored like below * values = 1 * 3 * 2 * 4 */ private double values[][]; /**Constant value set to 1*/ public static final DoubleNumberToken one = new DoubleNumberToken(1); /**Constant value set to 0*/ public static final DoubleNumberToken zero = new DoubleNumberToken(0); /**Constant value set to j*/ public static final DoubleNumberToken j = new DoubleNumberToken(0,1); /** Constructor creating empty number token */ public DoubleNumberToken() { // empty number token super(5, "double"); sizeY = 0; sizeX = 0; sizeA = new int[]{0,0}; noElem = 0; values = null; } /** Constructor creating a scalar taking the numbers value as a double * @param _value = the numbers value as a double */ public DoubleNumberToken(double _value) { this(_value, 0); } /** Constructor taking the numbers value as a double[][] * @param _value = the numbers value as a 2D array of double */ public DoubleNumberToken(double[][] _values) { this(_values, null); } /**Constructor taking the numbers value as a string * @param _real = the numbers real value as a string * @param _imaginary = the numbers imaginary value as a string */ public DoubleNumberToken(String _real, String _imaginary) { super(5, "double"); sizeX = 1; sizeY = 1; sizeA = new int[]{1, 1}; noElem = 1; values = new double[1][2]; // create real part if (_real!=null) values[0][REAL] = new Double(_real).doubleValue(); else values[0][REAL] = 0.0; // create imaginary part if (_imaginary!=null) values[0][IMAG] = new Double(_imaginary).doubleValue(); else values[0][IMAG] = 0.0; } /**Constructor taking the numbers value as a pair of double * values representing real and imaginary part * @param _real = the numbers real value as a double * @param _imaginary = the numbers imaginary value as a double */ public DoubleNumberToken(double _real, double _imaginary) { super(5, "double"); sizeX = 1; sizeY = 1; sizeA = new int[]{1, 1}; noElem = 1; values = new double[1][2]; values[0][REAL] = _real; values[0][IMAG] = _imaginary; } /**Constructor taking the numbers value as two double[][] * @param _real = the numbers value as a 2D array of double * @param _imaginary = the numbers value as a 2D array of double */ public DoubleNumberToken(double[][] _real, double[][] _imaginary) { super(5, "double"); if (_real!=null) { sizeY = _real.length; sizeX = _real[0].length; } else if(_imaginary!=null) { sizeY = _imaginary.length; sizeX = _imaginary[0].length; } sizeA = new int[]{sizeY, sizeX}; noElem = sizeY * sizeX; values = new double[noElem][2]; for(int xx = 0; xx < sizeX; xx++) { for(int yy = 0; yy < sizeY; yy++) { if (_real != null) values[xx*sizeY+yy][REAL] = _real[yy][xx]; else values[xx*sizeY+yy][REAL] = 0; if (_imaginary != null) values[xx*sizeY+yy][IMAG] = _imaginary[yy][xx]; else values[xx*sizeY+yy][IMAG] = 0; } } } /**Constructor taking the numbers value as a double[][][] * @param _values = the numbers value as a 3D array of double */ public DoubleNumberToken(double[][][] _values) { super(5, "double"); sizeY = _values.length; sizeX = _values[0].length; sizeA = new int[]{sizeY, sizeX}; noElem = sizeY * sizeX; values = new double[noElem][2]; for(int xx = 0; xx < sizeX; xx++) { for(int yy = 0; yy < sizeY; yy++) { values[xx*sizeY+yy][REAL] = _values[yy][xx][REAL]; values[xx*sizeY+yy][IMAG] = _values[yy][xx][IMAG]; } } } /** * * @param _dy * @param _dx * @param _reValues * @param _imValues */ public DoubleNumberToken(int _dy, int _dx, double[] _reValues, double[] _imValues) { super(5, "double"); sizeY = _dy; sizeX = _dx; sizeA = new int[]{sizeY, sizeX}; noElem = sizeY * sizeX; values = new double[noElem][2]; if ((_reValues != null) && (noElem != _reValues.length) ) Errors.throwMathLibException("DoubleNumberToken: real dimension mismatch"); if ((_imValues != null) && (noElem != _imValues.length) ) Errors.throwMathLibException("DoubleNumberToken: imag dimension mismatch"); for(int ni = 0; ni< noElem; ni++) { if (_reValues != null) values[ni][REAL] = _reValues[ni]; else values[ni][REAL] = 0.0; if (_imValues != null) values[ni][IMAG] = _imValues[ni]; else values[ni][IMAG] = 0.0; } } /** * Constructor for multidimensional array * @param _sizeA * @param _reValues * @param _imValues */ public DoubleNumberToken(int[] _sizeA, double[] _reValues, double[] _imValues) { super(5, "double"); sizeA = _sizeA; if (sizeA.length<2) Errors.throwMathLibException("DoubleNumberToken: dimension too low <2"); sizeY = sizeA[0]; sizeX = sizeA[1]; // compute number of elements over all dimensions noElem = 1; for (int i=0; i<sizeA.length; i++) { noElem *= sizeA[i]; } values = new double[noElem][2]; if ((_reValues != null) && (noElem != _reValues.length) ) Errors.throwMathLibException("DoubleNumberToken: real dimension mismatch"); if ((_imValues != null) && (noElem != _imValues.length) ) Errors.throwMathLibException("DoubleNumberToken: imag dimension mismatch"); for(int ni = 0; ni< noElem; ni++) { if (_reValues != null) values[ni][REAL] = _reValues[ni]; else values[ni][REAL] = 0.0; if (_imValues != null) values[ni][IMAG] = _imValues[ni]; else values[ni][IMAG] = 0.0; } } /** return a new Number Token of size y*x * @param x * @param y * @return */ public DataToken getElementSized(int y, int x) { return new DoubleNumberToken(y, x, new double[y*x],null); } /** increase/decrease the size of the current DoubleNumberToken to size y*x * @param dy number of rows * @param dx number of columns */ public void setSize(int dy, int dx) { double[][] newValues = new double[dy*dx][2]; ErrorLogger.debugLine("number "+dy+" "+dx); ErrorLogger.debugLine("number "+sizeY+" "+sizeX); // new array must be bigger than original value, otherwise values will be // lost after copying into the new array if ((dy<sizeY) || (dx<sizeX)) Errors.throwMathLibException("DoubleNumberToken: setSize: loosing values"); for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { int n = yx2n(yy,xx); ErrorLogger.debugLine("number "+yy+" "+xx); newValues[xx*dy + yy][REAL] = values[n][REAL]; newValues[xx*dy + yy][IMAG] = values[n][IMAG]; } } values = newValues; sizeY = dy; sizeX = dx; sizeA = new int[]{sizeY, sizeX}; noElem = sizeY * sizeX; } // end setSize /** * @return the real value of the first number */ public double getValueRe() { return getValueRe(0); } /** * @param y * @param x * @return the real value of the number at position y, x */ public double getValueRe(int y, int x) { return getValueRe( yx2n(y,x) ); } /** * @param index * @return */ public double getValueRe(int[] index) { return getValueRe( index2n(index) ); } /** * @param n * @return */ public double getValueRe(int n) { return values[n][REAL]; } /** * @param y * @param x * @return the real value of the number at position y, x as an integer */ public int getIntValue(int y, int x) { double temp = getValueRe( yx2n(y,x) ); return (new Double(temp)).intValue(); } /** * @return the imaginary value of the first number */ public double getValueIm() { return getValueIm(0); } /** * @param y * @param x * @return the imaginary value of the number at position y, x */ public double getValueIm(int y, int x) { return getValueIm( yx2n(y,x) ); } /** * @param index * @return */ public double getValueIm(int[] index) { return getValueIm( index2n(index) ); } /** * @param n * @return */ public double getValueIm(int n) { return values[n][IMAG]; } /** * @param y * @param x * @return the absolute value of the number at position y, x * */ public double getValueAbs(int y, int x) { int n = yx2n(y,x); double temp = Math.pow(values[n][REAL], 2) + Math.pow(values[n][IMAG], 2); return Math.sqrt(temp); } /** * @param y * @param x * @return the angle of the number at position y, x in radians */ public double getValueArg(int y, int x) { int n = yx2n(y,x); return Math.atan2(values[n][IMAG], values[n][REAL]); } /** * @return the real values of the number */ public double[][] getValuesRe() { double[][] temp = new double[sizeY][sizeX]; if ((sizeY==0) && (sizeX==0)) return null; for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { int n = yx2n(yy,xx); temp[yy][xx] = values[n][REAL]; } } return temp; } /** * @return the real values of the number */ public double[][] getReValues() { return getValuesRe(); } /** * @return the imaginary values of the number */ public double[][] getValuesIm() { double[][] temp = new double[sizeY][sizeX]; if ((sizeY==0) && (sizeX==0)) return null; for(int yy = 0; yy < sizeY; yy++) { for(int xx = 0; xx < sizeX; xx++) { int n = yx2n(yy,xx); temp[yy][xx] = values[n][IMAG]; } } return temp; } /** * @param n * @return */ public OperandToken getElement(int n) { return new DoubleNumberToken(values[n][REAL], values[n][IMAG]); } /** * @param n * @param num */ public void setElement(int n, OperandToken num) { values[n][REAL] = ((DoubleNumberToken)num).getValueRe(); values[n][IMAG] = ((DoubleNumberToken)num).getValueIm(); } /** * @param y = y position in matrix * @param x = x position in matrix * @return an array of double representing the element at y,x */ public double[] getValueComplex(int y, int x) { int n = yx2n(y,x); return getValueComplex(n); } /** * @param n * @return */ public double[] getValueComplex(int n) { return values[n]; } /** * @param n * @param _value */ public void setValueComplex(int n, double[] _value) { values[n] = _value; } /**Set value at position y, x * @param y = y position in matrix * @param x = x position in matrix * @param _value = the value to set it to as an array of doubles */ public void setValueComplex(int y, int x, double[] _value) { int n = yx2n(y,x); values[n][REAL] = _value[REAL]; values[n][IMAG] = _value[IMAG]; } /** Set value at position y, x * @param y = y position in matrix * @param x = x position in matrix * @param real = real value * @param imag = imaginary value */ public void setValue(int y, int x, double _real, double _imag) { int n = yx2n(y,x); setValue(n, _real, _imag); } /** * @param n * @param _real * @param _imag */ public void setValue(int n, double _real, double _imag) { values[n][REAL] = _real; values[n][IMAG] = _imag; } /** * @param index multidimensional index * @param _real * @param _imag */ public void setValue(int[] index, double _real, double _imag) { int n = index2n(index); setValue(n, _real, _imag); } /**return the number as a string * @return */ public String toString() { String result = null; if((sizeY == 0) && (sizeX == 0)) { // e.g. a=null; result = "[]"; } else if((sizeY == 1) && (sizeX == 1) && sizeA.length==2) { // e.g. a=555; result = toString(values[0]); } else if (sizeA.length ==2) { result = toString2d(new int[]{sizeY,sizeX}); } else { // e.g. a=[1,2,3;4,5,6] or multidimensional int[] dim = new int[sizeA.length]; dim[0] = sizeY; dim[1] = sizeX; String s = toString(dim, sizeA.length-1); result = new String(s); } return result; } /** * @param dim * @param i * @return */ private String toString(int[] dim, int i) { String ret=""; if (i>=2) { // e.g. at least 3rd dimension // e.g. a(5,3,4,x,3,1) for (int n=0; n<sizeA[i]; n++) { dim[i]=n; // e.g. a(5,3,Y,x,3,1) ret += toString(dim, i-1); } } else { // e.g. ret += "(:,:"; for (int k=2; k<dim.length; k++) { ret += "," + (dim[k]+1); //NOTE: conversion from internal to external index } ret += ") = \n"; ret += toString2d(dim); ret += "\n"; } return ret; } /** * @param nn * @return */ private String toString2d(int[] nn) { StringBuffer buffer = new StringBuffer(20); for(int yy = 0; yy < sizeA[0]; yy++) { buffer.append(" ["); for(int xx = 0; xx < sizeA[1]; xx++) { nn[0] = yy; nn[1] = xx; int n = index2n(nn); //ErrorLogger.debugLine(" NToken: "+index2n(nn)); buffer.append(toString(values[n])); if(xx < sizeX - 1) buffer.append(" , "); } buffer.append("]\n"); } return buffer.toString(); } /** create string representation of (complex) double values * @param _values[]={REAL,IMAG} real and imaginary part of number * @return */ public String toString(double _values[]) { if (_values==null) return "XXXXXX"; double re = _values[REAL]; double im = _values[IMAG]; StringBuffer result = new StringBuffer(); if((im != 0.0) || Double.isNaN(im)) result.append("("); // real part of number // +/- infinity, not a number, number if (re == Double.POSITIVE_INFINITY) result.append("Inf"); else if (re == Double.NEGATIVE_INFINITY) result.append("-Inf"); else if (Double.isNaN(re)) result.append("NaN"); else //result.append(getNumberFormat().format(re)); result.append(numFormat.format(re)); //stefan // imaginary part of number if((im != 0.0) || Double.isNaN(im)) { if ((re!=0.0) && !(im<0)) result.append("+"); // +/- infinity, not a number, number if (im == Double.POSITIVE_INFINITY) result.append("Inf"); else if (im == Double.NEGATIVE_INFINITY) result.append("-Inf"); else if (Double.isNaN(im)) result.append("NaN"); else //result.append(getNumberFormat().format(im)); result.append(numFormat.format(im)); //stefan result.append("i)"); } return result.toString(); } /**Evaluate the token. This causes it to return itself*/ //public OperandToken evaluate(Token[] operands) //{ // return this; //} /**Check if two tokens are equal * @param arg = the object to check against * @return */ public boolean equals(Object arg) { if(arg instanceof DoubleNumberToken) { DoubleNumberToken nArg = (DoubleNumberToken)arg; if(sizeX == nArg.getSizeX() && sizeY == nArg.getSizeY()) { boolean equal = true; for (int yy=0; yy<sizeY && equal; yy++) { for (int xx=0; xx<sizeX && equal; xx++) { int n = yx2n(yy,xx); if((values[n][REAL] - nArg.getValueRe(n) != 0) || (values[n][IMAG] - nArg.getValueIm(n) != 0) ) equal = false; } } return equal; } return false; } return false; } /**calculate the arg of the complex number at y, x * @param y * @param x * @return */ public double arg(int y, int x) { int n = yx2n(y,x); return Math.atan2(values[n][REAL], values[n][IMAG]); } ///////////////////////standard operators/////////////////// //////////////////////////////////////////////////////////// /**add arg to this object for a number token * @param = the value to add to it * @return the result as an OperandToken */ public OperandToken add(OperandToken arg) { if(arg instanceof DoubleNumberToken) { DoubleNumberToken nArg = ((DoubleNumberToken)arg); // Check dimensions of matrices if(checkEqualDimensions(sizeA, nArg.sizeA)) { // Add (n*m) + (n*m) or // same dimensions (n,m,r)==(n,m,r) ErrorLogger.debugLine("DoubleNumberToken: add (n*m) + (n*m)"); DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for(int n = 0; n < noElem; n++) { double real = getValueRe(n) + nArg.getValueRe(n); double imag = getValueIm(n) + nArg.getValueIm(n); result.setValue(n, real, imag); } //ErrorLogger.debugLine("end DoubleNumberToken: add (n*m) + (n*m)"); return result; } else if(isScalar()) { // 1 + [3,4,5] ErrorLogger.debugLine("DoubleNumberToken: add (1*1) + (n*m)"); DoubleNumberToken result = new DoubleNumberToken(nArg.sizeA, null, null); for(int n = 0; n < nArg.getNumberOfElements(); n++) { double realval = getValueRe() + nArg.getValueRe(n); double imaginaryval = getValueIm() + nArg.getValueIm(n); result.setValue(n, realval, imaginaryval); } //ErrorLogger.debugLine("end DoubleNumberToken: add (n*m) + (n*m)"); return result; } else if(nArg.isScalar()) { // [3,4,5] +1 ErrorLogger.debugLine("DoubleNumberToken: add (n,m) + (1,1)"); DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for(int n = 0; n < noElem; n++) { double realval = getValueRe(n) + nArg.getValueRe(); double imaginaryval = getValueIm(n) + nArg.getValueIm(); result.setValue(n, realval, imaginaryval); } //ErrorLogger.debugLine("end DoubleNumberToken: add (n*m) + (n*m)"); return result; } else { /* Matrices have unequal size: (n*m) != (o*p) */ Errors.throwMathLibException("DoubleNumberToken: add matrices of unequal size"); return null; } } else if(arg instanceof Int8NumberToken) { // transform: double + int8 into int8 + double Int8NumberToken nArg = ((Int8NumberToken)arg); return nArg.add(this); } else if(arg instanceof CharToken) { // 2+'a b' double[][] d = ((CharToken)arg).getValuesRe(); DoubleNumberToken num = new DoubleNumberToken(d); return this.add(num); } Errors.throwMathLibException("DoubleNumberToken: add: no number"); return null; } // and add /**subtract arg from this object for a number token * @param = the value to subtract * @return the result as an OperandToken */ public OperandToken subtract(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: substract: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); //Check dimensions of matrices if( checkEqualDimensions(this.sizeA, nArg.sizeA) ) { // Sub (n*m) - (n*m) or // multidimensional (n*m*r) - (n*m*r) ErrorLogger.debugLine("DoubleNumberToken: sub (n*m) - (n*m)"); DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for(int n = 0; n < noElem; n++) { double realval = getValueRe(n) - nArg.getValueRe(n); double imaginaryval = getValueIm(n) - nArg.getValueIm(n); result.setValue(n, realval, imaginaryval); } return result; } else if( isScalar() ) { // 1 - [2,3,4] ErrorLogger.debugLine("DoubleNumberToken: sub (1*1) - (n*m)"); DoubleNumberToken result = new DoubleNumberToken(nArg.sizeA, null, null); for(int n = 0; n < nArg.getNumberOfElements(); n++) { double realval = getValueRe() - nArg.getValueRe(n); double imaginaryval = getValueIm() - nArg.getValueIm(n); result.setValue(n, realval, imaginaryval); } return result; } else if( nArg.isScalar() ) { // [3,4,5] - 5 ErrorLogger.debugLine("DoubleNumberToken: sub (n*m) - (1*1)"); DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for(int n = 0; n < noElem; n++) { double realval = values[n][REAL] - nArg.getValueRe(); double imaginaryval = values[n][IMAG] - nArg.getValueIm(); result.setValue(n, realval, imaginaryval); } return result; } else { // Matrices have unequal size: (n*m) != (o*p) Errors.throwMathLibException("DoubleNumberToken: sub matrices of unequal size"); return null; } } /**Raise this object to the power of arg * @param = the value to raise it to the power of * @return the result as an OperandToken */ public OperandToken power(OperandToken arg) { // works only on numbers if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: powerOf: no number"); // get operand data and size DoubleNumberToken nArg = (DoubleNumberToken)arg; double[][] argValuesRe = ((DoubleNumberToken)arg).getValuesRe(); double[][] argValuesIm = ((DoubleNumberToken)arg).getValuesIm(); int argSizeX = ((DoubleNumberToken)arg).getSizeX(); int argSizeY = ((DoubleNumberToken)arg).getSizeY(); if ( this.isScalar() ) { // e.g. 4.^[1,2,3;4,5,6] // return values double [][][]results = new double[argSizeY][argSizeX][2]; for (int y=0; y<argSizeY; y++) { for (int x=0; x<argSizeX; x++) { if ((values[0][REAL]==0) && (values[0][IMAG]==0) && (argValuesRe[y][x]==0) && (argValuesIm[y][x]==0) ) { // 0^[1,0,3] -> [0,1,0] results[y][x][REAL] = 1.0; results[y][x][IMAG] = 0.0; } else if ((values[0][REAL]==0) && (values[0][IMAG]==0) && (argValuesRe[y][x]!=0) && (argValuesIm[y][x]==0) ) { // 0^[1,0,3] -> [0,1,0] results[y][x][REAL] = 0.0; results[y][x][IMAG] = 0.0; } else { double re = Math.log(getValueAbs(0, 0)); double im = getValueArg(0, 0); double re2 = (re*argValuesRe[y][x]) - (im*argValuesIm[y][x]); double im2 = (re*argValuesIm[y][x]) + (im*argValuesRe[y][x]); double scalar = Math.exp(re2); results[y][x][REAL] = scalar * Math.cos(im2); results[y][x][IMAG] = scalar * Math.sin(im2); } } } return new DoubleNumberToken(results); } else if ( nArg.isScalar() ) { // e.g. [1,2,3;4,5,6].^2 // return values double [][][]results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { if ((getValueRe(y,x)==0) && (getValueIm(y,x)==0) && ((argValuesRe[0][0]==0) && (argValuesIm[0][0]==0)) ) { // [1,0,3].^0 -> [1,0,1] results[y][x][REAL] = 1.0; results[y][x][IMAG] = 0.0; } else if ((getValueRe(y,x)==0) && (getValueIm(y,x)==0) && ((argValuesRe[0][0]!=0) && (argValuesIm[0][0]==0)) ) { // [2,0,3].^2 -> [4,1,9] results[y][x][REAL] = 0.0; results[y][x][IMAG] = 0.0; } else { double re = Math.log(getValueAbs(y, x)); double im = getValueArg(y, x); double re2 = (re*argValuesRe[0][0]) - (im*argValuesIm[0][0]); double im2 = (re*argValuesIm[0][0]) + (im*argValuesRe[0][0]); double scalar = Math.exp(re2); results[y][x][REAL] = scalar * Math.cos(im2); results[y][x][IMAG] = scalar * Math.sin(im2); } } } return new DoubleNumberToken(results); } else if ( checkEqualDimensions(this.sizeA, nArg.sizeA) ) { // e.g. [1,2,3;4,5,6].^[3,4,5;6,7,8] // return values double [][][]results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { double re = Math.log(getValueAbs(y, x)); double im = getValueArg(y, x); double re2 = (re*argValuesRe[y][x]) - (im*argValuesIm[y][x]); double im2 = (re*argValuesIm[y][x]) + (im*argValuesRe[y][x]); double scalar = Math.exp(re2); results[y][x][REAL] = scalar * Math.cos(im2); results[y][x][IMAG] = scalar * Math.sin(im2); } } return new DoubleNumberToken(results); } Errors.throwMathLibException("DoubleNumberToken: .^ dimensions do not fit"); return null; } // end powerOf /** The value to raise it to the matrix power of * @param arg * @return */ public OperandToken mPower(OperandToken arg) { // works only on numbers if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: mPower: no number"); // get operand data and size DoubleNumberToken nArg = (DoubleNumberToken)arg; double[][] argValuesRe = ((DoubleNumberToken)arg).getValuesRe(); double[][] argValuesIm = ((DoubleNumberToken)arg).getValuesIm(); int argSizeX = ((DoubleNumberToken)arg).getSizeX(); int argSizeY = ((DoubleNumberToken)arg).getSizeY(); if (this.isScalar() && (argSizeX==1) && (argSizeY==1)) { // e.g. 4.^5 // return values double [][][]results = new double[1][1][2]; double re = Math.log(getValueAbs(0, 0)); double im = getValueArg(0, 0); double re2 = (re*argValuesRe[0][0]) - (im*argValuesIm[0][0]); double im2 = (re*argValuesIm[0][0]) + (im*argValuesRe[0][0]); double scalar = Math.exp(re2); results[0][0][REAL] = scalar * Math.cos(im2); results[0][0][IMAG] = scalar * Math.sin(im2); return new DoubleNumberToken(results); } else if ((sizeX==sizeY) && (argSizeX==1) && (argSizeY==1)) { // [2,3;4,5]^9 Errors.throwMathLibException("DoubleNumberToken: mPower: [n*n]^scalar not implemented yet"); return null; } else if ((sizeX==1) && (sizeY==1) && (argSizeX==argSizeY)) { // 9^[2,3;4,5] Errors.throwMathLibException("DoubleNumberToken: mPower: scalar^[n*n] not implemented yet"); return null; } Errors.throwMathLibException("DoubleNumberToken: mPower: [n*m]^[o*p] not supported"); return null; } // end matrixPower /**multiply arg by this object for a number token * @param arg = the value to multiply it by * @return the result as an OperandToken */ public OperandToken multiply(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: multiply: no number"); DoubleNumberToken nArg = (DoubleNumberToken)arg; DoubleNumberToken argValues = ((DoubleNumberToken)arg); int argSizeX = ((DoubleNumberToken)arg).getSizeX(); int argSizeY = ((DoubleNumberToken)arg).getSizeY(); /* Check if arg is a scalar */ if( nArg.isScalar() ) { // Multiply (n*m) = (n*m) * scalar ErrorLogger.debugLine("DoubleNumberToken: multiply ("+sizeY+"*"+sizeX+") * scalar"); double [][][]results = new double[sizeY][sizeX][2]; double argRe = argValues.getValueRe(); double argIm = argValues.getValueIm(); for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { int n = yx2n(yy,xx); double temp = values[n][REAL] * argRe - values[n][IMAG] * argIm; results[yy][xx][IMAG] = values[n][IMAG] * argRe + values[n][REAL] * argIm; results[yy][xx][REAL] = temp; } } return new DoubleNumberToken(results); } else if( this.isScalar() ) { /* the DoubleNumberToken of this class is a scalar */ /* Multiply (n*m) = scalar * (n*m) */ ErrorLogger.debugLine("DoubleNumberToken: multiply scalar * (n*m) "); //argValues = argValues.times(values.get(0,0)); //values[0][0] = multiply(values[0][0], argValues.getValueComplex(0, 0)); return arg.multiply(this); } else if (sizeX == argSizeY && (sizeA.length==2)) { /* Multiply (n*o) = (n*m) * (m*o) */ ErrorLogger.debugLine("DoubleNumberToken: multiply (n*m) * (m*o)"); //Zmat resultValues = values.times(argValues); double[][][] results = new double[sizeY][argSizeX][2]; for(int i=0; i<sizeY; i++) { for (int k=0; k<argSizeX; k++) { results[i][k][REAL] = 0; results[i][k][IMAG] = 0; for (int j=0; j<sizeX; j++) { int n = yx2n(i,j); double temp[] = multiply(values[n], argValues.getValueComplex(j, k)); results[i][k][REAL] += temp[REAL]; results[i][k][IMAG] += temp[IMAG]; } } } return new DoubleNumberToken(results); } else { /* dimensions do not match */ Errors.throwMathLibException("DoubleNumberToken: multiply: dimensions don't match"); return null; } } // end multiply /**Multiplies two complex numbers * @param arg1 = the first complex number as an array of double * @param arg2 = the second complex number as an array of double * @return the result as an array of double */ public double[] multiply(double[] arg1, double[]arg2) { double[] temp = new double[2]; temp[REAL] = (arg1[REAL] * arg2[REAL]) - (arg1[IMAG] * arg2[IMAG]); temp[IMAG] = (arg1[REAL] * arg2[IMAG]) + (arg1[IMAG] * arg2[REAL]); return temp; } /**divide this object by arg for a number token * @param arg = the value to divide it by * @return the result as an OperandToken */ public OperandToken divide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: divide: no number"); DoubleNumberToken nArg = (DoubleNumberToken)arg; int argSizeX = nArg.getSizeX(); int argSizeY = nArg.getSizeY(); // Check if arg is a scalar if( nArg.isScalar() ) { // Divide (n*m) = (n*m) / scalar DoubleNumberToken result = new DoubleNumberToken(); //this); result.setSize(sizeY, sizeX); double[] argValue = nArg.getValueComplex(0, 0); ErrorLogger.debugLine("DoubleNumberToken: divide (n*m) / scalar"); for (int yy=0; yy<sizeY; yy++) { for (int xx=0; xx<sizeX; xx++) { int n = yx2n(yy,xx); result.setValueComplex(yy, xx, divide(values[n], argValue)); } } return result; } else if( this.isScalar() ) { // the DoubleNumberToken of this class is a scalar // Divide (n*m) = scalar / (n*m) ErrorLogger.debugLine("DoubleNumberToken: divide scalar / (n*m) "); DoubleNumberToken result = new DoubleNumberToken(1); double[] value = values[0]; for (int yy=0; yy<argSizeY; yy++) { for (int xx=0; xx<argSizeX; xx++) { result.setValueComplex(yy, xx, divide(value, nArg.getValueComplex(yy, xx))); } } return result; } else { Errors.throwMathLibException("DoubleNumberToken: divide: dimensions don't match"); return null; } } // end divide /** divide two complex numbers and return a complex number again, pay special attention to infinity and not a number @param arg1 = the first complex number as an array of double @param arg2 = the second complex number as an array of double @return the result as an array of double*/ public double[] divide(double[] arg1, double[] arg2) { /* {REAL,IMAG} = divide( {REAL,IMAG}, {REAL,IMAG}) */ double x = arg2[REAL]; double y = arg2[IMAG]; double zRe, zIm; double scalar; double[] temp = new double[2]; if ((x==0.0) && (y==0.0)) { // something like 1/0 50/0 or 0/0 // real part if (Double.isNaN(arg1[REAL])) zRe = Double.NaN; else if (arg1[REAL]>0) zRe = Double.POSITIVE_INFINITY; else if (arg1[REAL]<0) zRe = Double.NEGATIVE_INFINITY; else zRe = Double.NaN; // something like (1+i)/0 50i/0 // imaginary part if (Double.isNaN(arg1[IMAG])) zIm = Double.NaN; else if (arg1[IMAG]>0) zIm = Double.POSITIVE_INFINITY; else if (arg1[IMAG]<0) zIm = Double.NEGATIVE_INFINITY; else zIm = 0.0; } else if(Math.abs(x) >= Math.abs(y)) { scalar = 1.0 / ( x + y*(y/x) ); zRe = scalar * (arg1[REAL] + arg1[IMAG]*(y/x)); zIm = scalar * (arg1[IMAG] - arg1[REAL]*(y/x)); } else { scalar = 1.0 / ( x*(x/y) + y ); zRe = scalar * (arg1[REAL]*(x/y) + arg1[IMAG]); zIm = scalar * (arg1[IMAG]*(x/y) - arg1[REAL]); } temp[REAL] = zRe; temp[IMAG] = zIm; return temp; } //////////////////////////////////////////SCALAR OPERATORS////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// /**scalar multiply arg by this object for a number token @arg = the value to multiply it by @return the result as an OperandToken*/ public OperandToken scalarMultiply(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: scalar multiply: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); if ( checkEqualDimensions(this.sizeA, nArg.sizeA) ) { // scalar multiplication (n*m) = (n*m) .* (n*m) ErrorLogger.debugLine("DoubleNumberToken: multiply (n*m) .* (n*m)"); DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for (int n=0; n<noElem; n++) { double[] argVal = nArg.getValueComplex(n); result.setValueComplex(n, multiply(values[n], argVal) ); } return result; } else if ( nArg.isScalar() ) { // scalar multiplication (n*m) .* (1*1) ErrorLogger.debugLine("DoubleNumberToken: multiply (n*m) .* (1*1)"); DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for (int n=0; n<noElem; n++) { double[] argVal = nArg.getValueComplex(0); result.setValueComplex(n, multiply(values[n], argVal) ); } return result; } else if ( this.isScalar() ) { // scalar multiplication (1*1) .* (n*m) ErrorLogger.debugLine("DoubleNumberToken: multiply (1*1) .* (n*m)"); DoubleNumberToken result = new DoubleNumberToken(nArg.sizeA, null, null); for (int n=0; n<nArg.noElem; n++) { double[] argVal = nArg.getValueComplex(n); result.setValueComplex(n, multiply(values[0], argVal) ); } return result; } else { //dimensions do not match Errors.throwMathLibException("DoubleNumberToken: scalar multiply: dimensions don't match"); return null; } } // end scalarMultiply /**scalar divide arg by this object for a number token @arg = the value to divide it by @return the result as an OperandToken*/ public OperandToken scalarDivide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: scalar divide: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); double[][] argValues = nArg.getValuesRe(); double[][] argValuesImg = nArg.getValuesIm(); int argSizeX = nArg.getSizeX(); int argSizeY = nArg.getSizeY(); ErrorLogger.debugLine("DoubleNumberToken: scalarDivide. " +sizeY+" "+sizeX+" "+argSizeY+" "+argSizeX); if ((sizeX == argSizeX) && (sizeY == argSizeY)) { // divide multiplication (n*m) = (n*m) .* (n*m) ErrorLogger.debugLine("DoubleNumberToken: scalar divide (n*m) .* (n*m)"); double[][][] results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { int n = yx2n(y,x); double[] argVal = nArg.getValueComplex(y, x); results[y][x] = divide(values[n], argVal); } } return new DoubleNumberToken(results); } else if ( nArg.isScalar() ) { // divide multiplication (n*m) ./ (1,1) ErrorLogger.debugLine("DoubleNumberToken: scalar divide (n*m) ./ (1*1)"); double[][][] results = new double[sizeY][sizeX][2]; for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { int n = yx2n(y,x); double[] argVal = nArg.getValueComplex(0, 0); results[y][x] = divide(values[n], argVal); } } return new DoubleNumberToken(results); } else if ( this.isScalar() ) { // divide multiplication (n*m) ./ (1,1) ErrorLogger.debugLine("DoubleNumberToken: scalar divide (1*1) ./ (n*m)"); double[][][] results = new double[argSizeY][argSizeX][2]; for (int y=0; y<argSizeY; y++) { for (int x=0; x<argSizeX; x++) { double[] val = getValueComplex(0, 0); results[y][x] = divide(val, nArg.getValueComplex(y,x) ); } } return new DoubleNumberToken(results); } else { //dimensions do not match Errors.throwMathLibException("DoubleNumberToken: scalar multiply: dimensions don't match"); return null; } } // end scalarDivide /**left divide @arg = @return the result as an OperandToken*/ public OperandToken leftDivide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: left divide: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); DoubleNumberToken num = new DoubleNumberToken(nArg.getReValues()); //return num.divide(new DoubleNumberToken(values)); return num.divide(new DoubleNumberToken( this.getValuesRe(),this.getValuesIm() )); } // end leftDivide /**scalar left divide @arg = @return the result as an OperandToken*/ public OperandToken scalarLeftDivide(OperandToken arg) { if(!(arg instanceof DoubleNumberToken)) Errors.throwMathLibException("DoubleNumberToken: scalar left divide: no number"); DoubleNumberToken nArg = ((DoubleNumberToken)arg); DoubleNumberToken num = new DoubleNumberToken(nArg.getReValues()); //return num.scalarDivide(new DoubleNumberToken(values)); return num.scalarDivide(new DoubleNumberToken(this.getValuesRe(),this.getValuesIm())); } // end scalarLeftDivide /**calculate the transpose of a matrix @return the result as an OperandToken*/ public OperandToken transpose() { // transposed array double[][] real = new double[sizeX][sizeY]; double[][] imag = new double[sizeX][sizeY]; // swap rows and columns for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { int n = yx2n(y,x); // copy (y,x) -> (x,y), also change sign of imaginary part real[x][y] = values[n][REAL]; imag[x][y] = values[n][IMAG] * (-1); } } return new DoubleNumberToken(real, imag); } /**calculate the conjugate transpose of a matrix @return the result as an OperandToken*/ public OperandToken ctranspose() { // transposed array double[][] real = new double[sizeX][sizeY]; double[][] imag = new double[sizeX][sizeY]; // swap rows and columns for (int y=0; y<sizeY; y++) { for (int x=0; x<sizeX; x++) { int n = yx2n(y,x); // copy (y,x) -> (x,y), for conjugate transpose do not // change sign of imaginary part real[x][y] = values[n][REAL]; imag[x][y] = values[n][IMAG] ; } } return new DoubleNumberToken(real, imag); } ///////////////////////////////////////Standard Math Functions/////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// /**standard function - returns the negative of the number*/ public OperandToken negate() { DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for(int n = 0; n < noElem; n++) { result.setValue(n, -getValueRe(n), -getValueIm(n) ); } return result; } /**Standard functions - calculates the factorial of the number @return the result as an OperandToken*/ public OperandToken factorial() { DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for(int n = 0; n < noElem; n++) { double amount = Math.rint(getValueRe(n)); result.setValue(n, factorial(amount) , 0 ); } return result; } /**Calulates the factorial of a real value @param amount = the number to calc the factorial of @return the result as a double*/ public double factorial(double amount) { double answer = 1; for(int count = 1; count <= amount; count++) answer *= count; return answer; } //////////////////////////////////////Complex Functions///////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /**Complex function - calculates the complex conjugate of the number*/ public OperandToken conjugate() { DoubleNumberToken result = new DoubleNumberToken(sizeA, null, null); for(int n = 0; n < noElem; n++) { result.setValue(n, getValueRe(n) , -getValueIm(n) ); } return result; } //////////////////////////////////////Test Functions/////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// /**Checks if this operand is zero @return true if this number == 0 or that all values are 0 for a matrix*/ public boolean isNull() { for (int n=0; n<noElem; n++) { if( (getValueRe(n)!=0) || (getValueIm(n)!=0) ) return false; } return true; } /**@return true if this number token is a real matrix, without an imaginary part*/ public boolean isReal() { // if at least one element has an imaginary part the matrix is not real for (int n=0; n<noElem; n++) { if (getValueIm(n) != 0) return false; } return true; } /**@return true if this number token is an imaginary matrix, without a real part*/ public boolean isImaginary() { // if at least one element has a real part the matrix is not imaginary for (int n=0; n<noElem; n++) { if (getValueIm(n) != 0) return false; } return true; } /**@return true if this number token is a complex matrix with both real and imaginary parts*/ public boolean isComplex() { // if at least one element has a real value and also on element has // an imaginary part the matrix is complex boolean isRe = false; boolean isIm = false; for (int n=0; n<noElem; n++) { if (getValueRe(n) != 0) isRe = true; if (getValueIm(n)!= 0) isIm = true; } // check if both real and imaginary tags are set if (isRe && isIm) return true; else return false; } } // end DoubleNumberToken