public void validateExpression()

in src/main/java/org/apache/sysds/parser/BuiltinFunctionExpression.java [131:758]


	public void validateExpression(MultiAssignmentStatement stmt, HashMap<String, DataIdentifier> ids, HashMap<String, ConstIdentifier> constVars, boolean conditional)
	{
		if (this.getFirstExpr() instanceof FunctionCallIdentifier){
			raiseValidateError("UDF function call not supported as parameter to built-in function call", false);
		}
		
		this.getFirstExpr().validateExpression(ids, constVars, conditional);
		Expression [] expr = getAllExpr();
		if(expr != null && expr.length > 1) {
			for(int i = 1; i < expr.length; i++) {
				if (expr[i] instanceof FunctionCallIdentifier){
					raiseValidateError("UDF function call not supported as parameter to built-in function call", false);
				}
				expr[i].validateExpression(ids, constVars, conditional);
			}
		}
		_outputs = new Identifier[stmt.getTargetList().size()];
		int count = 0;
		for (DataIdentifier outParam: stmt.getTargetList()){
			DataIdentifier tmp = new DataIdentifier(outParam);
			tmp.setParseInfo(this);
			_outputs[count++] = tmp;
		}
		
		switch (_opcode) {
		case QR:
			checkNumParameters(1);
			checkMatrixParam(getFirstExpr());
			
			// setup output properties
			DataIdentifier qrOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier qrOut2 = (DataIdentifier) getOutputs()[1];
			
			long rows = getFirstExpr().getOutput().getDim1();
			long cols = getFirstExpr().getOutput().getDim2();
			
			// Output1 - Q
			qrOut1.setDataType(DataType.MATRIX);
			qrOut1.setValueType(ValueType.FP64);
			qrOut1.setDimensions(rows, cols);
			qrOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			// Output2 - R
			qrOut2.setDataType(DataType.MATRIX);
			qrOut2.setValueType(ValueType.FP64);
			qrOut2.setDimensions(rows, cols);
			qrOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			break;

		case LU:
			checkNumParameters(1);
			checkMatrixParam(getFirstExpr());
			
			// setup output properties
			DataIdentifier luOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier luOut2 = (DataIdentifier) getOutputs()[1];
			DataIdentifier luOut3 = (DataIdentifier) getOutputs()[2];
			
			long inrows = getFirstExpr().getOutput().getDim1();
			long incols = getFirstExpr().getOutput().getDim2();

			if (inrows != incols) {
				raiseValidateError("LU Decomposition requires a square matrix. Matrix " + getFirstExpr() + " is "
						+ inrows + "x" + incols + ".", conditional);
			}

			// Output1 - P
			luOut1.setDataType(DataType.MATRIX);
			luOut1.setValueType(ValueType.FP64);
			luOut1.setDimensions(inrows, inrows);
			luOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			// Output2 - L
			luOut2.setDataType(DataType.MATRIX);
			luOut2.setValueType(ValueType.FP64);
			luOut2.setDimensions(inrows, inrows);
			luOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			// Output3 - U
			luOut3.setDataType(DataType.MATRIX);
			luOut3.setValueType(ValueType.FP64);
			luOut3.setDimensions(inrows, inrows);
			luOut3.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			break;

		case LSTM:
		{
			//TODO: LSTM on GPU has different INPUT/OUTPUT than LSTM on CPU

			// X,  W, bias, out0, c0, return_sequences
			checkNumParameters(6);
			checkMatrixParam(getFirstExpr());
			checkMatrixParam(getSecondExpr());
			checkMatrixParam(getThirdExpr());
			checkMatrixParam(getFourthExpr());
			checkMatrixParam(getFifthExpr());
			
			// setup output properties, on CPU there are 3 more additionally outputs (cache_out, cache_c, cache_ifog)
			if(getOutputs() == null || (getOutputs().length != 2 && getOutputs().length != 5)) {
				int numOutputs = getOutputs() == null ? 0 : getOutputs().length;
				raiseValidateError("The builtin function lstm has two outputs, but instead found: " + numOutputs, conditional);
			}
			DataIdentifier out = (DataIdentifier) getOutputs()[0];
			DataIdentifier cy = (DataIdentifier) getOutputs()[1];
			
			// Output1 - out: If `return_sequences` is True, outputs for all timesteps, else outputs for the final timestep.
			out.setDataType(DataType.MATRIX);
			out.setValueType(ValueType.FP64);
			out.setDimensions(-1, -1);
			out.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			// Output2 - Cell state for final timestep.
			cy.setDataType(DataType.MATRIX);
			cy.setValueType(ValueType.FP64);
			cy.setDimensions(getExpr(4).getOutput().getDim1(), getExpr(4).getOutput().getDim2());
			cy.setBlocksize(getExpr(4).getOutput().getBlocksize());

			if(getOutputs().length == 5){
				DataIdentifier cache_out = (DataIdentifier) getOutputs()[2];
				DataIdentifier cache_c = (DataIdentifier) getOutputs()[3];
				DataIdentifier cache_ifog = (DataIdentifier) getOutputs()[4];

				// Output3 - cache_out: (T,N*M) T is unknown upfront
				cache_out.setDataType(DataType.MATRIX);
				cache_out.setValueType(ValueType.FP64);
				cache_out.setDimensions(-1, -1);
				cache_out.setBlocksize(getFirstExpr().getOutput().getBlocksize());

				// Output4 - cache_c: (T,N*M)
				cache_c.setDataType(DataType.MATRIX);
				cache_c.setValueType(ValueType.FP64);
				cache_out.setDimensions(-1, -1);
				cache_out.setBlocksize(getFirstExpr().getOutput().getBlocksize());

				// Output5 - cache_ifog: (T,N*M)
				cache_ifog.setDataType(DataType.MATRIX);
				cache_ifog.setValueType(ValueType.FP64);
				cache_ifog.setDimensions(-1, -1);
				cache_ifog.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			}
			break;
		}
		case LSTM_BACKWARD:
		{
			// Input: X, W, b, out0, c0, return_sequences, dout, cy
			checkNumParameters(8);
			checkMatrixParam(getFirstExpr());
			checkMatrixParam(getSecondExpr());
			checkMatrixParam(getThirdExpr());
			checkMatrixParam(getFourthExpr());
			checkMatrixParam(getFifthExpr());
			checkMatrixParam(getSeventhExpr());
			checkMatrixParam(getEighthExpr());
			
			// Output: dx, dw, db, dout0, dc0
			// setup output properties
			if(getOutputs().length != 5)
				raiseValidateError("lstm_backward has 5 outputs", false);
			 
			DataIdentifier dx = (DataIdentifier) getOutputs()[0];
			DataIdentifier dw = (DataIdentifier) getOutputs()[1];
			DataIdentifier db = (DataIdentifier) getOutputs()[2];
			DataIdentifier dout0 = (DataIdentifier) getOutputs()[3];
			DataIdentifier dc0 = (DataIdentifier) getOutputs()[4];
			
			setDimensions(dx, getFirstExpr());
			setDimensions(dw, getSecondExpr());
			setDimensions(db, getThirdExpr());
			setDimensions(dout0, getFourthExpr());
			setDimensions(dc0, getFifthExpr());
			break;
		}
		case BATCH_NORM2D:
		{
			// Input: image, scale, bias, runningMean, runningVar, mode, epsilon, exponentialAverageFactor
			checkNumParameters(8);
			checkMatrixParam(getFirstExpr());
			checkMatrixParam(getSecondExpr());
			checkMatrixParam(getThirdExpr());
			checkMatrixParam(getFourthExpr());
			checkMatrixParam(getFifthExpr());
			
			// Output: ret, retRunningMean, retRunningVar, resultSaveMean, resultSaveInvVariance
			// setup output properties
			if(getOutputs().length != 5)
				raiseValidateError("batch_norm2d has 5 outputs", false);
			 
			DataIdentifier ret = (DataIdentifier) getOutputs()[0];
			DataIdentifier retRunningMean = (DataIdentifier) getOutputs()[1];
			DataIdentifier retRunningVar = (DataIdentifier) getOutputs()[2];
			DataIdentifier resultSaveMean = (DataIdentifier) getOutputs()[3];
			DataIdentifier resultSaveInvVariance = (DataIdentifier) getOutputs()[4];
			
			setDimensions(ret, getFirstExpr());
			setDimensions(retRunningMean, getFourthExpr());
			setDimensions(retRunningVar, getFourthExpr());
			setDimensions(resultSaveMean, getFourthExpr());
			setDimensions(resultSaveInvVariance, getFourthExpr());
			break;
		}
		case BATCH_NORM2D_BACKWARD:
		{
			// Input: image, dout, scale, epsilon, savedMean, savedInvVariance
			checkNumParameters(6);
			checkMatrixParam(getFirstExpr());
			checkMatrixParam(getSecondExpr());
			checkMatrixParam(getThirdExpr());
			checkMatrixParam(getFifthExpr());
			checkMatrixParam(getSixthExpr());
			
			// Output: dX, dScale, dBias 
			// setup output properties
			if(getOutputs().length != 3)
				raiseValidateError("batch_norm2d_backward has 3 outputs", false);
			
			DataIdentifier dX = (DataIdentifier) getOutputs()[0];
			DataIdentifier dScale = (DataIdentifier) getOutputs()[1];
			DataIdentifier dBias = (DataIdentifier) getOutputs()[2];
			
			setDimensions(dX, getFirstExpr());
			setDimensions(dScale, getThirdExpr());
			setDimensions(dBias, getThirdExpr());
			break;
		}
		case EIGEN: {
			checkNumParameters(1);
			checkMatrixParam(getFirstExpr());
			
			// setup output properties
			DataIdentifier eigenOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier eigenOut2 = (DataIdentifier) getOutputs()[1];
			
			if ( getFirstExpr().getOutput().getDim1() != getFirstExpr().getOutput().getDim2() ) {
				raiseValidateError("Eigen Decomposition can only be done on a square matrix. Input matrix is rectangular (rows=" + getFirstExpr().getOutput().getDim1() + ", cols="+ getFirstExpr().getOutput().getDim2() +")", conditional);
			}
			
			// Output1 - Eigen Values
			eigenOut1.setDataType(DataType.MATRIX);
			eigenOut1.setValueType(ValueType.FP64);
			eigenOut1.setDimensions(getFirstExpr().getOutput().getDim1(), 1);
			eigenOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			// Output2 - Eigen Vectors
			eigenOut2.setDataType(DataType.MATRIX);
			eigenOut2.setValueType(ValueType.FP64);
			eigenOut2.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			eigenOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			break;
		}
		case RCM: {
			checkNumParameters(2);
			checkMatrixParam(getFirstExpr());
			checkMatrixParam(getSecondExpr());
			long nr = Math.max(getFirstExpr().getOutput().getDim1(),
				getSecondExpr().getOutput().getDim1());
			long nc = Math.max(getFirstExpr().getOutput().getDim2(),
				getSecondExpr().getOutput().getDim2());
			for(int i=0; i<2; i++) {
				DataIdentifier out = (DataIdentifier) getOutputs()[i];
				out.setDataType(DataType.MATRIX);
				out.setValueType(ValueType.FP64);
				out.setDimensions(nr, nc);
				out.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			}
			break;
		}
		case FFT: {

			Expression expressionOne = getFirstExpr();
			Expression expressionTwo = getSecondExpr();

			if(expressionOne == null) {
				raiseValidateError("The first argument to " + _opcode + " cannot be null.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionOne.getOutput() == null || expressionOne.getOutput().getDim1() == 0 ||
				expressionOne.getOutput().getDim2() == 0) {
				raiseValidateError("The first argument to " + _opcode + " cannot be an empty matrix.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionTwo != null) {
				raiseValidateError("Too many arguments. This FFT implementation is only defined for real inputs.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(!isPowerOfTwo(expressionOne.getOutput().getDim1()) ||
				!isPowerOfTwo(expressionOne.getOutput().getDim2())) {
				raiseValidateError(
					"This FFT implementation is only defined for matrices with dimensions that are powers of 2.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}

			checkNumParameters(1);
			checkMatrixParam(expressionOne);

			DataIdentifier fftOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier fftOut2 = (DataIdentifier) getOutputs()[1];

			fftOut1.setDataType(DataType.MATRIX);
			fftOut1.setValueType(ValueType.FP64);
			fftOut1.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			fftOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			fftOut2.setDataType(DataType.MATRIX);
			fftOut2.setValueType(ValueType.FP64);
			fftOut2.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			fftOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			break;

		}
		case IFFT: {
			Expression expressionTwo = getSecondExpr();
			Expression expressionOne = getFirstExpr();

			if(expressionOne == null) {
				raiseValidateError("The first argument to " + _opcode + " cannot be null.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionOne.getOutput() == null || expressionOne.getOutput().getDim1() == 0 ||
				expressionOne.getOutput().getDim2() == 0) {
				raiseValidateError("The first argument to " + _opcode + " cannot be an empty matrix.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionTwo != null) {
				if(expressionTwo.getOutput() == null || expressionTwo.getOutput().getDim1() == 0 ||
					expressionTwo.getOutput().getDim2() == 0) {
					raiseValidateError("The second argument to " + _opcode
						+ " cannot be an empty matrix. Provide either only a real matrix or a filled real and imaginary one.",
						false, LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}

			checkNumParameters(expressionTwo != null ? 2 : 1);
			checkMatrixParam(expressionOne);
			if(expressionTwo != null && expressionOne != null) {
				checkMatrixParam(expressionTwo);
				if(expressionOne.getOutput().getDim1() != expressionTwo.getOutput().getDim1() ||
					expressionOne.getOutput().getDim2() != expressionTwo.getOutput().getDim2())
					raiseValidateError("The real and imaginary part of the provided matrix are of different dimensions.",
						false);
				else if(!isPowerOfTwo(expressionTwo.getOutput().getDim1()) ||
					!isPowerOfTwo(expressionTwo.getOutput().getDim2())) {
					raiseValidateError(
						"This IFFT implementation is only defined for matrices with dimensions that are powers of 2.", false,
						LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}
			else if(expressionOne != null) {
				if(!isPowerOfTwo(expressionOne.getOutput().getDim1()) ||
					!isPowerOfTwo(expressionOne.getOutput().getDim2())) {
					raiseValidateError(
						"This IFFT implementation is only defined for matrices with dimensions that are powers of 2.", false,
						LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}

			DataIdentifier ifftOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier ifftOut2 = (DataIdentifier) getOutputs()[1];

			ifftOut1.setDataType(DataType.MATRIX);
			ifftOut1.setValueType(ValueType.FP64);
			ifftOut1.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			ifftOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			// Output2 - ifft Vectors
			ifftOut2.setDataType(DataType.MATRIX);
			ifftOut2.setValueType(ValueType.FP64);
			ifftOut2.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			ifftOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			break;
		}
		case FFT_LINEARIZED: {

			Expression expressionOne = getFirstExpr();
			Expression expressionTwo = getSecondExpr();

			if(expressionOne == null) {
				raiseValidateError("The first argument to " + _opcode + " cannot be null.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionOne.getOutput() == null || expressionOne.getOutput().getDim1() == 0 ||
				expressionOne.getOutput().getDim2() == 0) {
				raiseValidateError("The first argument to " + _opcode + " cannot be an empty matrix.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionTwo != null) {
				raiseValidateError(
					"Too many arguments. This FFT_LINEARIZED implementation is only defined for real inputs.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(!isPowerOfTwo(expressionOne.getOutput().getDim2())) {
				raiseValidateError(
					"This FFT_LINEARIZED implementation is only defined for matrices with columns that are powers of 2.",
					false, LanguageErrorCodes.INVALID_PARAMETERS);
			}

			checkNumParameters(1);
			checkMatrixParam(expressionOne);

			DataIdentifier fftOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier fftOut2 = (DataIdentifier) getOutputs()[1];

			fftOut1.setDataType(DataType.MATRIX);
			fftOut1.setValueType(ValueType.FP64);
			fftOut1.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			fftOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			fftOut2.setDataType(DataType.MATRIX);
			fftOut2.setValueType(ValueType.FP64);
			fftOut2.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			fftOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			break;

		}
		case IFFT_LINEARIZED: {
			Expression expressionTwo = getSecondExpr();
			Expression expressionOne = getFirstExpr();

			if(expressionOne == null) {
				raiseValidateError("The first argument to " + _opcode + " cannot be null.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionOne.getOutput() == null || expressionOne.getOutput().getDim1() == 0 ||
				expressionOne.getOutput().getDim2() == 0) {
				raiseValidateError("The first argument to " + _opcode + " cannot be an empty matrix.", false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(expressionTwo != null) {
				if(expressionTwo.getOutput() == null || expressionTwo.getOutput().getDim1() == 0 ||
					expressionTwo.getOutput().getDim2() == 0) {
					raiseValidateError("The second argument to " + _opcode
						+ " cannot be an empty matrix. Provide either only a real matrix or a filled real and imaginary one.",
						false, LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}

			checkNumParameters(expressionTwo != null ? 2 : 1);
			checkMatrixParam(expressionOne);
			if(expressionTwo != null && expressionOne != null) {
				checkMatrixParam(expressionTwo);
				if(expressionOne.getOutput().getDim1() != expressionTwo.getOutput().getDim1() ||
					expressionOne.getOutput().getDim2() != expressionTwo.getOutput().getDim2())
					raiseValidateError("The real and imaginary part of the provided matrix are of different dimensions.",
						false);
				else if(!isPowerOfTwo(expressionTwo.getOutput().getDim2())) {
					raiseValidateError(
						"This IFFT_LINEARIZED implementation is only defined for matrices with columns that are powers of 2.",
						false, LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}
			else if(expressionOne != null) {
				if(!isPowerOfTwo(expressionOne.getOutput().getDim2())) {
					raiseValidateError(
						"This IFFT_LINEARIZED implementation is only defined for matrices with columns that are powers of 2.",
						false, LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}

			DataIdentifier ifftOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier ifftOut2 = (DataIdentifier) getOutputs()[1];

			ifftOut1.setDataType(DataType.MATRIX);
			ifftOut1.setValueType(ValueType.FP64);
			ifftOut1.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			ifftOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			ifftOut2.setDataType(DataType.MATRIX);
			ifftOut2.setValueType(ValueType.FP64);
			ifftOut2.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			ifftOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			break;
		}
		case STFT: {
			checkMatrixParam(getFirstExpr());

			if((getFirstExpr() == null || getSecondExpr() == null || getThirdExpr() == null) && _args.length > 0) {
				raiseValidateError("Missing argument for function " + this.getOpCode(), false,
					LanguageErrorCodes.INVALID_PARAMETERS);
			}
			else if(getFifthExpr() != null) {
				raiseValidateError("Invalid number of arguments for function " + this.getOpCode().toString().toLowerCase()
					+ "(). This function only takes 3 or 4 arguments.", false);
			}
			else if(_args.length == 3) {
				checkScalarParam(getSecondExpr());
				checkScalarParam(getThirdExpr());
				if(!isPowerOfTwo(((ConstIdentifier) getSecondExpr().getOutput()).getLongValue())) {
					raiseValidateError(
						"This FFT implementation is only defined for matrices with dimensions that are powers of 2."
							+ "The window size (2nd argument) is not a power of two",
						false, LanguageErrorCodes.INVALID_PARAMETERS);
				}
				else if(((ConstIdentifier) getSecondExpr().getOutput())
					.getLongValue() <= ((ConstIdentifier) getThirdExpr().getOutput()).getLongValue()) {
					raiseValidateError("Overlap can't be larger than or equal to the window size.", false,
						LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}
			else if(_args.length == 4) {
				checkMatrixParam(getSecondExpr());
				checkScalarParam(getThirdExpr());
				checkScalarParam(getFourthExpr());
				if(!isPowerOfTwo(((ConstIdentifier) getThirdExpr().getOutput()).getLongValue())) {
					raiseValidateError(
						"This FFT implementation is only defined for matrices with dimensions that are powers of 2."
							+ "The window size (3rd argument) is not a power of two",
						false, LanguageErrorCodes.INVALID_PARAMETERS);
				}
				else if(getFirstExpr().getOutput().getDim1() != getSecondExpr().getOutput().getDim1() ||
					getFirstExpr().getOutput().getDim2() != getSecondExpr().getOutput().getDim2()) {
					raiseValidateError("The real and imaginary part of the provided matrix are of different dimensions.",
						false);
				}
				else if(((ConstIdentifier) getThirdExpr().getOutput())
					.getLongValue() <= ((ConstIdentifier) getFourthExpr().getOutput()).getLongValue()) {
					raiseValidateError("Overlap can't be larger than or equal to the window size.", false,
						LanguageErrorCodes.INVALID_PARAMETERS);
				}
			}

			// setup output properties
			DataIdentifier stftOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier stftOut2 = (DataIdentifier) getOutputs()[1];

			// Output1 - stft Values
			stftOut1.setDataType(DataType.MATRIX);
			stftOut1.setValueType(ValueType.FP64);
			stftOut1.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			stftOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			// Output2 - stft Vectors
			stftOut2.setDataType(DataType.MATRIX);
			stftOut2.setValueType(ValueType.FP64);
			stftOut2.setDimensions(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());
			stftOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			break;
		}
		case REMOVE: {
			checkNumParameters(2);
			checkListParam(getFirstExpr());
			
			// setup output properties
			DataIdentifier out1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier out2 = (DataIdentifier) getOutputs()[1];
			
			// Output1 - list after removal
			long nrow = getFirstExpr().getOutput().getDim1() > 0 ? 
				getFirstExpr().getOutput().getDim1() + 1 : -1;
			out1.setDataType(DataType.LIST);
			out1.setValueType(getFirstExpr().getOutput().getValueType());
			out1.setDimensions(nrow, 1);
			out1.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			// Output2 - list of removed element
			out2.setDataType(DataType.LIST);
			out2.setValueType(getFirstExpr().getOutput().getValueType());
			out2.setDimensions(1, 1);
			out2.setBlocksize(getFirstExpr().getOutput().getBlocksize());
			
			break;
		}
		case SVD:
			checkNumParameters(1);
			checkMatrixParam(getFirstExpr());
			
			long minMN = Math.min(getFirstExpr().getOutput().getDim1(), getFirstExpr().getOutput().getDim2());

			// setup output properties
			DataIdentifier svdOut1 = (DataIdentifier) getOutputs()[0];
			DataIdentifier svdOut2 = (DataIdentifier) getOutputs()[1];
			DataIdentifier svdOut3 = (DataIdentifier) getOutputs()[2];

			// Output 1
			svdOut1.setDataType(DataType.MATRIX);
			svdOut1.setValueType(ValueType.FP64);
			svdOut1.setDimensions(getFirstExpr().getOutput().getDim1(), minMN);
			svdOut1.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			// Output 2
			svdOut2.setDataType(DataType.MATRIX);
			svdOut2.setValueType(ValueType.FP64);
			svdOut2.setDimensions(minMN, minMN);
			svdOut2.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			// Output 3
			svdOut3.setDataType(DataType.MATRIX);
			svdOut3.setValueType(ValueType.FP64);
			svdOut3.setDimensions(getFirstExpr().getOutput().getDim2(), minMN);
			svdOut3.setBlocksize(getFirstExpr().getOutput().getBlocksize());

			break;

		case COMPRESS:
			if(OptimizerUtils.ALLOW_SCRIPT_LEVEL_COMPRESS_COMMAND) {
				Expression expressionTwo = getSecondExpr();
				checkNumParameters(getSecondExpr() != null ? 2 : 1);
				checkMatrixFrameParam(getFirstExpr());
				if(expressionTwo != null)
					checkMatrixParam(getSecondExpr());

				Identifier compressInput1 = getFirstExpr().getOutput();
				// Identifier compressInput2 = getSecondExpr().getOutput();

				DataIdentifier compressOutput = (DataIdentifier) getOutputs()[0];
				compressOutput.setDataType(DataType.MATRIX);
				compressOutput.setDimensions(compressInput1.getDim1(), compressInput1.getDim2());
				compressOutput.setBlocksize(compressInput1.getBlocksize());
				compressOutput.setValueType(compressInput1.getValueType());

				DataIdentifier metaOutput = (DataIdentifier) getOutputs()[1];
				metaOutput.setDataType(DataType.FRAME);
				metaOutput.setDimensions(compressInput1.getDim1(), -1);
			}
			else
				raiseValidateError("Compress/DeCompress instruction not allowed in dml script");
			break;

		default: //always unconditional
			raiseValidateError("Unknown Builtin Function opcode: " + _opcode, false);
		}
	}