All Downloads are FREE. Search and download functionalities are using the official Maven repository.

carosellini.rJava.JRI.0.9-7.source-code.REXP Maven / Gradle / Ivy

Go to download

JRI is a Java/R Interface, which allows to run R inside Java applications as a single thread. Basically it loads R dynamic library into Java and provides a Java API to R functionality. It supports both simple calls to R functions and a full running REPL.

The newest version!
package org.rosuda.JRI;

import java.util.Vector;

/**
 * This class encapsulates and caches R objects as returned from R. Currently it
 * only converts certain SEXPs references from R into Java obejcts, but
 * eventually bi-directional support should be added. The currently supported
 * objects are string, integer and numeric vectors. All other types can be
 * accessed only using {@link #xp} reference and RNI methods.
 */
public class REXP {
	/** xpression type: NULL */
	public static final int XT_NULL = 0;

	/** xpression type: integer */
	public static final int XT_INT = 1;

	/** xpression type: double */
	public static final int XT_DOUBLE = 2;

	/** xpression type: String */
	public static final int XT_STR = 3;

	/** xpression type: language construct (currently content is same as list) */
	public static final int XT_LANG = 4;

	/** xpression type: symbol (content is symbol name: String) */
	public static final int XT_SYM = 5;

	/** xpression type: RBool */
	public static final int XT_BOOL = 6;

	/** xpression type: Vector */
	public static final int XT_VECTOR = 16;

	/** xpression type: RList */
	public static final int XT_LIST = 17;
	
	/**
	 * xpression type: closure (there is no java class for that type (yet?).
	 * currently the body of the closure is stored in the content part of the
	 * REXP. Please note that this may change in the future!)
	 */
	public static final int XT_CLOS = 18;

	/** xpression type: int[] */
	public static final int XT_ARRAY_INT = 32;

	/** xpression type: double[] */
	public static final int XT_ARRAY_DOUBLE = 33;

	/** xpression type: String[] (currently not used, Vector is used instead) */
	public static final int XT_ARRAY_STR = 34;

	/** internal use only! this constant should never appear in a REXP */
	public static final int XT_ARRAY_BOOL_UA = 35;

	/** xpression type: RBool[] */
	public static final int XT_ARRAY_BOOL = 36;

	/** xpression type: int[] to be interpreted as boolean */
	public static final int XT_ARRAY_BOOL_INT = 37;

	/** xpression type: unknown; no assumptions can be made about the content */
	public static final int XT_UNKNOWN = 48;

	/** xpression type: pure reference, no internal type conversion performed */
	public static final int XT_NONE = -1;

	/**
	 * xpression type: RFactor; this XT is internally generated (ergo is does
	 * not come from Rsrv.h) to support RFactor class which is built from
	 * XT_ARRAY_INT
	 */
	public static final int XT_FACTOR = 127;

	/* internal SEXP types in R - taken directly from Rinternals.h */
	public static final int NILSXP = 0; /* nil = NULL */

	public static final int SYMSXP = 1; /* symbols */

	public static final int LISTSXP = 2; /* lists of dotted pairs */

	public static final int CLOSXP = 3; /* closures */

	public static final int ENVSXP = 4; /* environments */

	public static final int PROMSXP = 5; /*
											 * promises: [un]evaluated closure
											 * arguments
											 */

	public static final int LANGSXP = 6; /*
											 * language constructs (special
											 * lists)
											 */

	public static final int SPECIALSXP = 7; /* special forms */

	public static final int BUILTINSXP = 8; /* builtin non-special forms */

	public static final int CHARSXP = 9; /*
											 * "scalar" string type (internal
											 * only)
											 */

	public static final int LGLSXP = 10; /* logical vectors */

	public static final int INTSXP = 13; /* integer vectors */

	public static final int REALSXP = 14; /* real variables */

	public static final int CPLXSXP = 15; /* complex variables */

	public static final int STRSXP = 16; /* string vectors */

	public static final int DOTSXP = 17; /* dot-dot-dot object */

	public static final int ANYSXP = 18; /* make "any" args work */

	public static final int VECSXP = 19; /* generic vectors */

	public static final int EXPRSXP = 20; /* expressions vectors */

	public static final int BCODESXP = 21; /* byte code */

	public static final int EXTPTRSXP = 22; /* external pointer */

	public static final int WEAKREFSXP = 23; /* weak reference */

	public static final int RAWSXP = 24; /* raw bytes */

	public static final int S4SXP = 25; /* S4 object */

	public static final int FUNSXP = 99; /* Closure or Builtin */

	/**
	 * Engine which this EXP was obtained from. EXPs are valid only for the
	 * engine they were obtained from - it's illegal to mix EXP between engines.
	 * There is a speacial case when the engine may be null - if a REXP creating
	 * was requested but deferred until an engine is available.
	 */
	Rengine eng;

	/**
	 * native reference to the SEXP represented in R. It's usually a pointer,
	 * but can be any handle obtained from the engine. This reference can be
	 * used when calling RNI commands directly.
	 */
	public long xp;

	/**
	 * native type of the represented expression (see ...SXP constants in R).
	 * Please note that this type is cached and may have changed in the
	 * meantime. If the possibility of changing type exists (mainly list/lang)
	 * then use rniExpType to make sure
	 */
	public int rtype;

	/**
	 * create a REXP directly from a R SEXP reference. SEXP types STRSXP, INTSXP
	 * and REALSXP are automatically converted. All others are represented as
	 * SEXP references only.
	 */
	public REXP(Rengine re, long exp) {
		this(re, exp, true);
	}
	
	protected void finalize() throws Throwable {
		try {
			if (Xt == XT_NONE && xp != 0 && eng != null) // release underlying R obejct if it was preserved
				eng.rniRelease(xp);
		} finally {
			super.finalize();
		}
	}

	public REXP(Rengine re, long exp, boolean convert) {
		eng = re;
		xp = exp;
		rtype = re.rniExpType(xp);
		//System.out.println("["+rtype+"@"+exp+","+convert+"]");

		if (!convert) {
			Xt = XT_NONE;
			if (re != null && xp != 0)
				re.rniPreserve(xp); // preserve the object so it doesn't get garbage-collected while we are referencing it
			return;
		}
				
		if (rtype == STRSXP) {
			String[] s = re.rniGetStringArray(xp);
			if (s != null && s.length == 1) {
				cont = s[0];
				Xt = XT_STR;
			} else {
				cont = s;
				Xt = XT_ARRAY_STR;
			}
		} else if (rtype == INTSXP) {
			cont = null;
			if (re.rniInherits(xp, "factor")) {
				long levx = re.rniGetAttr(xp, "levels");
				if (levx != 0) {
					String[] levels = null;
					// we're using low-lever calls here (FIXME?)
					int rlt = re.rniExpType(levx);
					if (rlt == STRSXP) {
						levels = re.rniGetStringArray(levx);
						int[] ids = re.rniGetIntArray(xp);
						cont = new RFactor(ids, levels, 1);
						Xt = XT_FACTOR;
					}
				}
			}
			// if it's not a factor, then we use int[] instead
			if (cont == null ) {
				cont = re.rniGetIntArray(xp);
				Xt = XT_ARRAY_INT;
			}
		} else if (rtype == REALSXP) {
			cont = re.rniGetDoubleArray(xp);
			Xt = XT_ARRAY_DOUBLE;
		} else if (rtype == LGLSXP) {
		    cont = re.rniGetBoolArrayI(xp);
		    Xt = XT_ARRAY_BOOL_INT;
		} else if (rtype == VECSXP) {
			long[] l = re.rniGetVector(xp);
			cont = new RVector();
			int i = 0;
			//System.out.println("VECSXP, length="+l.length);
			Xt = XT_VECTOR;
			while (i < l.length)
				((RVector)cont).addElement(new REXP(re, l[i++]));
			long na = re.rniGetAttr(xp, "names");
			if (na!=0 && re.rniExpType(na)==STRSXP)
				((RVector)cont).setNames(re.rniGetStringArray(na));
		} else if (rtype == LISTSXP) {
			long car = re.rniCAR(xp);
			long cdr = re.rniCDR(xp);
			long tag = re.rniTAG(xp);

			REXP cdrx = (cdr==0 || re.rniExpType(cdr)!=LISTSXP)?null:new REXP(re,re.rniCDR(xp));
			cont = new RList(new REXP(re,car), (tag==0)?null:new REXP(re,tag), cdrx);
			Xt = XT_LIST;
		} else if (rtype == SYMSXP) {
			cont = re.rniGetSymbolName(xp);
			Xt = XT_SYM;
		} else
			Xt = XT_NULL;
		
		//System.out.println("new REXP: "+toString());
	}

	/** xpression type */
	int Xt;

	/** attribute xpression or null if none */
	REXP attr;

	/** content of the xpression - its object type is dependent of {@link #Xt} */
	Object cont;

	/** cached binary length; valid only if positive */
	long cachedBinaryLength = -1;

	/** construct a new, empty (NULL) expression w/o attribute */
	public REXP() {
		Xt = XT_NULL;
		attr = null;
		cont = null;
	}

	/**
	 * construct a new xpression of type t and content o, but no attribute
	 * 
	 * @param t
	 *            xpression type (XT_...)
	 * @param o
	 *            content
	 */
	public REXP(int t, Object o) {
		Xt = t;
		cont = o;
		attr = null;
	}

	/**
	 * construct a new xpression of type t, content o and attribute at
	 * 
	 * @param t
	 *            xpression type
	 * @param o
	 *            content
	 * @param at
	 *            attribute
	 */
	public REXP(int t, Object o, REXP at) {
		Xt = t;
		cont = o;
		attr = at;
	}

	/**
	 * construct a new xpression of type XT_ARRAY_DOUBLE and content val
	 * 
	 * @param val
	 *            array of doubles to store in the REXP
	 */
	public REXP(double[] val) {
		this(XT_ARRAY_DOUBLE, val);
	}

	/**
	 * construct a new xpression of type XT_ARRAY_INT and content val
	 * 
	 * @param val
	 *            array of integers to store in the REXP
	 */
	public REXP(int[] val) {
		this(XT_ARRAY_INT, val);
	}

	/**
	 * construct a new xpression of type XT_ARRAY_INT and content val
	 * 
	 * @param val
	 *            array of integers to store in the REXP
	 */
	public REXP(String[] val) {
		this(XT_ARRAY_STR, val);
	}

    /** construct new expression with the contents of a boolean vector
	@since JRI 0.3-2
	@param val contents */
	public REXP(boolean[] val) {
	    Xt = XT_ARRAY_BOOL_INT;
	    if (val==null) { cont = new int[0]; } else {
		int [] ic = new int[val.length];
		int i=0;
		while (inull if there is none associated
		@since JRI 0.3, replaces getAttribute() but should be avoided if possible - use {@link #getAttribute(String)} instead.
		*/
	public REXP getAttributes() {
		return attr;
	}

	/** retrieve a specific attribute.
Note: the current representation fetches the attribute ad-hoc, so it breaks the assumption that the expression is no longer accessed after the constructor was called. This should change in the future. @param name name of the attribute @return REXP containing the attribute or null if the attribute doesn't exist. The conversion flag is inherited from this REXP. @since JRI 0.3 */ public REXP getAttribute(String name) { // FIXME: we could do some caching if attr is not null ... long aref = eng.rniGetAttr(xp, name); if (aref==0) return null; return new REXP(eng, aref, (Xt != XT_NONE)); } /** * get raw content. Use as... methods to retrieve contents of known type. * * @return content of the REXP */ public Object getContent() { return cont; } /** * get xpression type (see XT_.. constants) of the content. It defines the * type of the content object. * * @return xpression type */ public int getType() { return Xt; } /** * Obtains R engine object which supplied this REXP. * * @returns {@link Rengine} object */ Rengine getEngine() { return eng; }; /** return the first element of a character vector if this REXP is a character vector of length 1 or more, return null otherwise */ public String asString() { if (cont == null) return null; if (Xt == XT_STR) return (String) cont; if (Xt == XT_ARRAY_STR) { String[] sa = (String[]) cont; return (sa.length > 0) ? sa[0] : null; } return null; } /** return the name of the symbol represented by this REXP if is it a symbol or null otherwise */ public String asSymbolName() { return (Xt == XT_SYM)?((String) cont):null; } /** return the contents of this REXP as an array of strings if this REXP is a character vector, return null otherwise */ public String[] asStringArray() { if (cont == null) return null; if (Xt == XT_STR) { String[] sa = new String[1]; sa[0] = (String) cont; return sa; } if (Xt == XT_ARRAY_STR) return (String[]) cont; return null; } /** * get content of the REXP as int (if it is one) * * @return int content or 0 if the REXP is no integer */ public int asInt() { if (Xt == XT_ARRAY_INT) { int i[] = (int[]) cont; if (i != null && i.length > 0) return i[0]; } return (Xt == XT_INT) ? ((Integer) cont).intValue() : 0; } /** * get content of the REXP as double (if it is one) * * @return double content or 0.0 if the REXP is no double */ public double asDouble() { if (Xt == XT_ARRAY_DOUBLE) { double d[] = (double[]) cont; if (d != null && d.length > 0) return d[0]; } return (Xt == XT_DOUBLE) ? ((Double) cont).doubleValue() : 0.0; } /** * get content of the REXP as {@link Vector} (if it is one) * * @return Vector content or null if the REXP is no Vector */ public RVector asVector() { return (Xt == XT_VECTOR) ? (RVector) cont : null; } /** * get content of the REXP as {@link RFactor} (if it is one) * * @return {@link RFactor} content or null if the REXP is no * factor */ public RFactor asFactor() { return (Xt == XT_FACTOR) ? (RFactor) cont : null; } /** * get content of the REXP as {@link RList} if the contents is a list or a generic vector * * @return {@link RList} content or null if the REXP is neither a list nor a generic vector */ public RList asList() { return (Xt == XT_LIST) ? (RList) cont : ( // for compatibility with Rserve we convert vectors to lists (Xt == XT_VECTOR) ? new RList((RVector)cont) : null ); } /** * get content of the REXP as {@link RBool} (if it is one) * * @return {@link RBool} content or null if the REXP is no * logical value */ public RBool asBool() { if (Xt == XT_ARRAY_BOOL_INT) { int [] ba = (int[]) cont; return (ba!=null && ba.length>0)?new RBool(ba[0]):null; } return (Xt == XT_BOOL) ? (RBool) cont : null; } /** * get content of the REXP as an array of doubles. Array of integers, single * double and single integer are automatically converted into such an array * if necessary. * * @return double[] content or null if the REXP is not a * array of doubles or integers */ public double[] asDoubleArray() { if (Xt == XT_ARRAY_DOUBLE) return (double[]) cont; if (Xt == XT_DOUBLE) { double[] d = new double[1]; d[0] = asDouble(); return d; } if (Xt == XT_INT) { double[] d = new double[1]; d[0] = ((Integer) cont).doubleValue(); return d; } if (Xt == XT_ARRAY_INT) { int[] i = asIntArray(); if (i == null) return null; double[] d = new double[i.length]; int j = 0; while (j < i.length) { d[j] = (double) i[j]; j++; } return d; } return null; } /** * get content of the REXP as an array of integers. Unlike * {@link #asDoubleArray} NO automatic conversion is done if the * content is not an array of the correct type, because there is no * canonical representation of doubles as integers. A single integer is * returned as an array of the length 1. This method can be also used * to access a logical array in its integer form (0=FALSE, 1=TRUE, 2=NA). * * @return int[] content or null if the REXP is not a * array of integers */ public int[] asIntArray() { if (Xt == XT_ARRAY_INT || Xt == XT_ARRAY_BOOL_INT) return (int[]) cont; if (Xt == XT_INT) { int[] i = new int[1]; i[0] = asInt(); return i; } return null; } /** * returns the content of the REXP as a matrix of doubles (2D-array: * m[rows][cols]). This is the same form as used by popular math packages * for Java, such as JAMA. This means that following leads to desired * results:
* Matrix m=new Matrix(c.eval("matrix(c(1,2,3,4,5,6),2,3)").asDoubleMatrix()); * * @return 2D array of doubles in the form double[rows][cols] or * null if the contents is no 2-dimensional matrix of * doubles */ public double[][] asDoubleMatrix() { double[] ct = asDoubleArray(); if (ct==null) return null; REXP dim = getAttribute("dim"); if (dim == null || dim.Xt != XT_ARRAY_INT) return null; // we need dimension attr int[] ds = dim.asIntArray(); if (ds == null || ds.length != 2) return null; // matrix must be 2-dimensional int m = ds[0], n = ds[1]; double[][] r = new double[m][n]; if (ct == null) return null; // R stores matrices as matrix(c(1,2,3,4),2,2) = col1:(1,2), col2:(3,4) // we need to copy everything, since we create 2d array from 1d array int i = 0, k = 0; while (i < n) { int j = 0; while (j < m) { r[j++][i] = ct[k++]; } i++; } return r; } /** this is just an alias for {@link #asDoubleMatrix()}. */ public double[][] asMatrix() { return asDoubleMatrix(); } /** * displayable contents of the expression. The expression is traversed * recursively if aggregation types are used (Vector, List, etc.) * * @return String descriptive representation of the xpression */ public String toString() { StringBuffer sb = new StringBuffer("[" + xtName(Xt) + " "); if (attr != null) sb.append("\nattr=" + attr + "\n "); if (Xt == XT_DOUBLE) sb.append((Double) cont); if (Xt == XT_INT) sb.append((Integer) cont); if (Xt == XT_BOOL) sb.append((RBool) cont); if (Xt == XT_FACTOR) sb.append((RFactor) cont); if (Xt == XT_ARRAY_DOUBLE) { double[] d = (double[]) cont; sb.append("("); for (int i = 0; i < d.length; i++) { sb.append(d[i]); if (i < d.length - 1) sb.append(", "); if (i == 99) { sb.append("... (" + (d.length - 100) + " more values follow)"); break; } } sb.append(")"); } if (Xt == XT_ARRAY_INT) { int[] d = (int[]) cont; sb.append("("); for (int i = 0; i < d.length; i++) { sb.append(d[i]); if (i < d.length - 1) sb.append(", "); if (i == 99) { sb.append("... (" + (d.length - 100) + " more values follow)"); break; } } sb.append(")"); } if (Xt == XT_ARRAY_BOOL) { RBool[] d = (RBool[]) cont; sb.append("("); for (int i = 0; i < d.length; i++) { sb.append(d[i]); if (i < d.length - 1) sb.append(", "); } sb.append(")"); } if (Xt == XT_ARRAY_STR) { String[] d = (String[]) cont; sb.append("("); for (int i = 0; i < d.length; i++) { sb.append((d[i] == null) ? "NA" : ("\"" + d[i] + "\"")); if (i < d.length - 1) sb.append(", "); if (i == 10 && d.length > 14) { sb.append("... (" + (d.length - 10) + " more values follow)"); break; } } sb.append(")"); } if (Xt == XT_VECTOR) { Vector v = (Vector) cont; sb.append("("); for (int i = 0; i < v.size(); i++) { sb.append(((REXP) v.elementAt(i)).toString()); if (i < v.size() - 1) sb.append(", "); } sb.append(")"); } if (Xt == XT_STR) { if (cont == null) sb.append("NA"); else { sb.append("\""); sb.append((String) cont); sb.append("\""); } } if (Xt == XT_SYM) { sb.append((String) cont); } if (Xt == XT_LIST || Xt == XT_LANG) { RList l = (RList) cont; sb.append(l.head); sb.append(":"); sb.append(l.tag); sb.append(",("); sb.append(l.body); sb.append(")"); } if (Xt == XT_NONE) { sb.append("{"+rtype+"}"); } if (Xt == XT_UNKNOWN) sb.append((Integer) cont); sb.append("]"); return sb.toString(); } public static String quoteString(String s) { // this code uses API introdiced in 1.4 so it needs to be re-written for // earlier JDKs if (s.indexOf('\\') >= 0) s.replaceAll("\\", "\\\\"); if (s.indexOf('"') >= 0) s.replaceAll("\"", "\\\""); return "\"" + s + "\""; } /** returns human-readable name of the xpression type as string. Arrays are denoted by a trailing asterisk (*). @param xt xpression type @return name of the xpression type */ public static String xtName(int xt) { if (xt==XT_NULL) return "NULL"; if (xt==XT_INT) return "INT"; if (xt==XT_STR) return "STRING"; if (xt==XT_DOUBLE) return "REAL"; if (xt==XT_BOOL) return "BOOL"; if (xt==XT_ARRAY_INT) return "INT*"; if (xt==XT_ARRAY_STR) return "STRING*"; if (xt==XT_ARRAY_DOUBLE) return "REAL*"; if (xt==XT_ARRAY_BOOL) return "BOOL*"; if (xt==XT_ARRAY_BOOL_INT) return "BOOLi*"; if (xt==XT_SYM) return "SYMBOL"; if (xt==XT_LANG) return "LANG"; if (xt==XT_LIST) return "LIST"; if (xt==XT_CLOS) return "CLOS"; if (xt==XT_VECTOR) return "VECTOR"; if (xt==XT_FACTOR) return "FACTOR"; if (xt==XT_UNKNOWN) return "UNKNOWN"; if (xt==XT_NONE) return "(SEXP)"; return ""; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy