📄 rmodel.java
字号:
package org.openscience.cdk.qsar.model.R2;import org.openscience.cdk.qsar.model.IModel;import org.openscience.cdk.qsar.model.QSARModelException;import org.openscience.cdk.tools.LoggingTool;import org.rosuda.JRI.REXP;import org.rosuda.JRI.RList;import org.rosuda.JRI.RMainLoopCallbacks;import org.rosuda.JRI.Rengine;import java.awt.*;import java.io.*;import java.util.HashMap;import java.util.Iterator;import java.util.Random;import java.util.Set;/** * Base class for the R-CDK interface. * <p/> * This class provides the basis for all classes that wish to interface with * R functions from a CDK program. * <p/> * Since the R engine is multi-threaded only one instance of the R session can exist * for a given Java process. This implies that initialization must be perfored exactly once * within a Java process. This class ensure that this occurs. * <p/> * In addition, this class loads some helper functions into the R session. The loading * can be via a temporary file (the default) or via a String, which may be useful in * webservice scenarios. * <p/> * <b>Requirement</b> The class (and implementing subclasses) is dependent on the * <a href="http://rosuda.org/JRI/">JRI</a> library. This provides an interface to R * for Java code. Though the <a href="http://rosuda.org/rJava/">rJava</a> for R * includes JRI, the code here is only dependent on JRI and does not attempt to * go from R to Java. Hence rJava is not a requirement. To compile this code, the CDK * includes the JRI jar file. However to run the code, the JRI native library (libjri.so * on Linux) must be located in the users LD_LIBRARY_PATH. Also the versions of the JRI Java * API and native library should match and this is checked for. * <p/> * Currently the CDK uses JRI 0.3 (available from <a href=" http://rosuda.org/R/nightly/other/JRI_0.3-0.tar.gz">here</a>) * <p/> * <p/> * <b>Implementation Notes</b> * <ul> * <li>If the user requires other initializations the only way to do so at * this point is to edit <code>helper.R</code> or perform the initialization by hand * <li>An implementing class must call <code>super()</code> * <li>Though this class provides a field to store the R model object as a * <code>RList</code> the actual R variable will remain in the R session. This is useful * for saving the model as a .Rda file at one point. Also by storing the model on the R * side we do not not need to make repeated queries on the model via <code>eval()</code>. * <li>Subclasses of this class are generally Java front-ends to a specific R model type * (such as linear regression, CNN etc.). Thus each subclass should provide getter methods * for the various components of such an object. Since this is tedious to do by hand, * you can use the <code>stubs.R</code> script that comes with the CDK distribution to * generate source code for the getter methods for the individual components of an R model * object. Note, that the script currently ignores objects of classes <code>'call'</code> * and <code>'formula'</code>. * </ul> * <p/> * <b>NOTE</b>: For the R backend to work, ensure that R is correctly installed. * Other requirements are * <ul> * <li>LD_LIBRARY_PATH should include the directory that contains <code>libjri.so</code> as well * as the dierctory that contains <code>libR.so</code> * <li>R_HOME should be set to the appropriate location * </ul> * * @author Rajarshi Guha * @cdk.require r-project * @cdk.require JRI.jar * @cdk.require java1.5+ * @cdk.module qsar * @cdk.keyword R * @cdk.keyword JRI */public abstract class RModel implements IModel { private String modelName = null; protected RList modelObject = null; protected HashMap params = null; /** * The object that performs the calls to the R engine. */ protected static Rengine rengine = null; /** * A boolean that indicates whether the R/Java subsystem has been initialized or not. */ private static boolean doneInit = false; private static LoggingTool logger; private void initRengine(String[] args, boolean useDisk) throws QSARModelException { if (!doneInit) { rengine = new Rengine(args, false, new TextConsole()); if (!rengine.waitForR()) { throw new QSARModelException("Could not load rJava"); } else { logger.debug("Started R"); } doneInit = true; if (useDisk) { loadRFunctions(rengine); logger.info("Initializing from disk"); } else { loadRFunctionsAsStrings(rengine); logger.info("Initializing from strings"); } logger.info("rJava initialized"); } else { logger.info("rjava already intialized"); } } private void loadRFunctions(Rengine engine) { // File.separator is used to be system independent // Fix me: After creating a jar file it don't work on a windwos OS // but within eclipse it won't work on while working with '/' on windows OS // No idea how to solve this // String scriptLocator = "org" + File.separator + "openscience" + // File.separator + "cdk" + File.separator + "qsar" + File.separator + // "model" + File.separator + "data" + File.separator + "helper.R"; String scriptLocator = "org/openscience/cdk/qsar/model/data/helper.R"; try { File scriptFile = File.createTempFile("XXXXX", ".R"); scriptFile.deleteOnExit(); InputStreamReader reader = new InputStreamReader( this.getClass().getClassLoader().getResourceAsStream(scriptLocator)); BufferedReader inFile = new BufferedReader(reader); FileWriter outFile = new FileWriter(scriptFile); BufferedWriter outBuffer = new BufferedWriter(outFile); String inputLine; while ((inputLine = inFile.readLine()) != null) { outBuffer.write(inputLine, 0, inputLine.length()); outBuffer.newLine(); } outBuffer.close(); inFile.close(); outFile.close(); // Necessary for windows user, R needs a '/' in the path of a file even on windows String path = scriptFile.getAbsolutePath(); path = path.replaceAll("\\\\", "/"); engine.eval("source(\"" + path + "\")"); } catch (Exception exception) { logger.error("Could not load helper R script for JRI: ", scriptLocator); logger.debug(exception); } } private void loadRFunctionsAsStrings(Rengine evaluator) { String[] scripts = { "helper.R", }; String scriptPrefix = "org/openscience/cdk/qsar/model/data/"; for (int i = 0; i < scripts.length; i++) { String scriptLocator = scriptPrefix + scripts[i]; try { InputStreamReader reader = new InputStreamReader( this.getClass().getClassLoader().getResourceAsStream(scriptLocator)); BufferedReader inFile = new BufferedReader(reader); StringWriter sw = new StringWriter(); String inputLine; while ((inputLine = inFile.readLine()) != null) { sw.write(inputLine); sw.write("\n"); } sw.close(); evaluator.eval("eval(parse(text=\"" + sw.toString() + "\"))"); } catch (Exception exception) { logger.error("Could not load CDK-rJava R scripts: ", scriptLocator); logger.debug(exception); } } } /** * Initializes R with the <i>--vanilla, --quiet, --slave</i> flags. * <p/> * This constructor will initialize the R session via a temporary file or * from a String depending on whether the symbol <code>initRFromString</code> * is specified on the command line */ public RModel() throws QSARModelException { // check that the JRI jar and .so match if (!Rengine.versionCheck()) { logger.debug("API version of the JRI library does not match that of the native binary"); throw new QSARModelException("API version of the JRI library does not match that of the native binary"); } params = new HashMap(); String[] args = {"--vanilla", "--quiet", "--slave"}; logger = new LoggingTool(this); String initRFromString = System.getProperty("initRFromString"); boolean useDisk = true; if (initRFromString != null && initRFromString.equals("true")) { useDisk = false; } initRengine(args, useDisk); } /** * Saves a R model to disk. * <p/> * This function can be used to save models built in a session, and then loaded * again in a different session. * * @param modelName The name of the model as returned by \code{getModelName}. * @param fileName The file to which the model should be saved * @throws QSARModelException if the R session cannot save the model * @see #loadModel */ public void saveModel(String modelName, String fileName) throws QSARModelException { if (fileName == null || fileName.equals("")) { fileName = modelName + ".rda"; } rengine.assign("tmpModelName", modelName); rengine.assign("tmpFileName", fileName); REXP result = rengine.eval("saveModel(tmpModelName, tmpFileName)"); if (result == null) { logger.debug("Error in 'saveModel(tmpModelName, tmpFileName)'"); throw new QSARModelException("Error saving model"); } } /** * Get the name of the model. * <p/> * This function returns the name of the variable that the actual * model is stored in within the R session. In general this is * not used for the end user. In the future this might be changed * to a private method. * * @return A String containing the name of the R variable * @see #setModelName */ public String getModelName() { return (this.modelName); } /** * Set the name of the model. * <p/> * Ordinarily the user does not need to call this function as each model * is assigned a unique ID at instantiation. However, if a user saves a model * to disk and then later loads it, the loaded * model may overwrite a model in that session. In this situation, this method * can be used to assign a name to the model. * * @param newName The name of the model * @see #getModelName * @see #saveModel * @see #loadModel */ public void setModelName(String newName) { if (this.modelName != null && this.modelName.equals(newName)) return; String oldName = this.modelName; if (oldName != null) { rengine.eval("if ('" + oldName + "' %in% ls()) {" + newName + "<-" + oldName + ";rm(" + oldName + ")}"); } this.modelName = newName; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -