001    /*
002     * Copyright (C) 2008-2010 by Holger Arndt
003     *
004     * This file is part of the Universal Java Matrix Package (UJMP).
005     * See the NOTICE file distributed with this work for additional
006     * information regarding copyright ownership and licensing.
007     *
008     * UJMP is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU Lesser General Public License as
010     * published by the Free Software Foundation; either version 2
011     * of the License, or (at your option) any later version.
012     *
013     * UJMP is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016     * GNU Lesser General Public License for more details.
017     *
018     * You should have received a copy of the GNU Lesser General Public
019     * License along with UJMP; if not, write to the
020     * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
021     * Boston, MA  02110-1301  USA
022     */
023    
024    package org.ujmp.core.util;
025    
026    import java.io.BufferedReader;
027    import java.io.BufferedWriter;
028    import java.io.File;
029    import java.io.IOException;
030    import java.io.InputStreamReader;
031    import java.io.OutputStreamWriter;
032    
033    import org.ujmp.core.Matrix;
034    import org.ujmp.core.enums.FileFormat;
035    
036    public class R {
037    
038            public static String[] SEARCH = new String[] {};
039    
040            static {
041                    try {
042                            SEARCH = new String[] { System.getProperty("R"), "/usr/bin/R", "/opt/R/bin/R" };
043                    } catch (Exception e) {
044                    }
045            }
046    
047            public static final int POLLINTERVAL = 100;
048    
049            public static final int MAXPOLLS = 10;
050    
051            private BufferedReader input = null;
052    
053            private BufferedWriter output = null;
054    
055            private BufferedReader error = null;
056    
057            private Process rProcess = null;
058    
059            private boolean running = false;
060    
061            private static R r = null;
062    
063            private static String pathToR = null;
064    
065            public static synchronized R getInstance() throws Exception {
066                    if (r == null) {
067                            r = getInstance(findR());
068                    }
069                    return r;
070            }
071    
072            public static synchronized R getInstance(String pathToR) throws Exception {
073                    if (r == null) {
074                            r = new R(pathToR);
075                    }
076                    return r;
077            }
078    
079            private R(String pathToR) throws Exception {
080                    rProcess = Runtime.getRuntime().exec(pathToR + " --no-save --no-readline");
081                    output = new BufferedWriter(new OutputStreamWriter(rProcess.getOutputStream()));
082                    input = new BufferedReader(new InputStreamReader(rProcess.getInputStream()));
083                    error = new BufferedReader(new InputStreamReader(rProcess.getErrorStream()));
084                    String startMessage = getFromR();
085                    if (startMessage != null && startMessage.length() > 0) {
086                            running = true;
087                            return;
088                    }
089                    throw new Exception("could not start R");
090            }
091    
092            private synchronized String getFromR() throws Exception {
093                    boolean lfSeen = false;
094                    StringBuilder sb = new StringBuilder();
095    
096                    for (int i = 0; i < MAXPOLLS; i++) {
097                            if (!input.ready()) {
098                                    Thread.sleep(POLLINTERVAL);
099                            } else {
100                                    break;
101                            }
102                    }
103    
104                    while (input.ready()) {
105    
106                            char c = (char) input.read();
107                            sb.append(c);
108    
109                            if (lfSeen) {
110                                    if (c == '>') {
111                                            return sb.toString();
112                                    } else {
113                                            lfSeen = false;
114                                    }
115                            }
116                            if (c == '\n') {
117                                    lfSeen = true;
118                            }
119    
120                    }
121                    return sb.toString();
122            }
123    
124            public String execute(String command) throws Exception {
125                    sendToR(command);
126                    String cur = "";
127                    String last = "";
128    
129                    cur = getFromR();
130    
131                    while (cur != null && cur.length() > 0) {
132                            last = cur;
133                            cur = getFromR();
134                    }
135    
136                    return last;
137            }
138    
139            public synchronized void shutdown() throws Exception {
140                    r = null;
141                    sendToR("q()");
142                    rProcess.waitFor();
143                    output.close();
144                    input.close();
145            }
146    
147            private synchronized void sendToR(String command) throws Exception {
148                    if (r != null) {
149                            try {
150                                    if (!command.endsWith("\n")) {
151                                            command += "\n";
152                                    }
153                                    output.write(command, 0, command.length());
154                                    output.flush();
155                            } catch (IOException e) {
156                                    shutdown();
157                            }
158                    }
159            }
160    
161            public void setMatrix(String label, Matrix matrix) throws Exception {
162                    execute(label + " <- " + matrix.exportToString(FileFormat.R));
163            }
164    
165            private static String findR() {
166                    if (pathToR == null) {
167                            File file = null;
168                            for (String s : SEARCH) {
169                                    if (s != null) {
170                                            file = new File(s);
171                                            if (file.exists()) {
172                                                    pathToR = file.getAbsolutePath();
173                                                    return pathToR;
174                                            }
175                                    }
176                            }
177                    }
178                    return pathToR;
179            }
180    
181            public Matrix getMatrix(String label) throws Exception {
182                    try {
183    
184                            String rawRows = execute("cat(nrow(" + label + "))");
185                            String rString = rawRows.split("\n")[1].replaceAll("\\>", "").trim();
186                            int rows = Integer.parseInt(rString);
187                            String rawCols = execute("cat(ncol(" + label + "))");
188                            String cString = rawCols.split("\n")[1].replaceAll("\\>", "").trim();
189                            int cols = Integer.parseInt(cString);
190    
191                            String rawText = execute("cat(" + label + ")");
192                            String[] rawValues = rawText.split("\n")[1].split("[\\s]+");
193    
194                            Matrix matrix = Matrix.factory.zeros(rows, cols);
195    
196                            int i = 0;
197                            for (int r = 0; r < rows; r++) {
198                                    for (int c = 0; c < cols; c++) {
199                                            matrix.setAsDouble(Double.parseDouble(rawValues[i++].replaceAll("\\>", "")
200                                                            .trim()), r, c);
201                                    }
202                            }
203    
204                            return matrix;
205                    } catch (Exception e) {
206                            e.printStackTrace();
207                            return null;
208                    }
209            }
210    
211            public static boolean isAvailable() {
212                    return findR() != null;
213            }
214    
215            public static String toString(String[] strings) {
216                    if (strings.length != 0) {
217                            return "," + strings[0];
218                    } else {
219                            return "";
220                    }
221            }
222    
223            public void plot(Matrix matrix, String... format) throws Exception {
224                    execute("X11()");
225                    setMatrix("ujmpmatrix", matrix);
226                    execute("plot(ujmpmatrix" + toString(format) + ")");
227            }
228    
229            public void pairs(Matrix matrix, String... format) throws Exception {
230                    execute("X11()");
231                    setMatrix("ujmpmatrix", matrix);
232                    execute("pairs(ujmpmatrix" + toString(format) + ")");
233            }
234    
235            public void qqnorm(Matrix matrix, String... format) throws Exception {
236                    execute("X11()");
237                    setMatrix("ujmpmatrix", matrix);
238                    execute("qqnorm(ujmpmatrix" + toString(format) + ")");
239            }
240    
241            public void hist(Matrix matrix, String... format) throws Exception {
242                    execute("X11()");
243                    setMatrix("ujmpmatrix", matrix);
244                    execute("hist(ujmpmatrix" + toString(format) + ")");
245            }
246    
247            public void image(Matrix matrix, String... format) throws Exception {
248                    execute("X11()");
249                    setMatrix("ujmpmatrix", matrix);
250                    execute("image(ujmpmatrix" + toString(format) + ")");
251            }
252    
253            public void boxplot(Matrix matrix, String... format) throws Exception {
254                    execute("X11()");
255                    setMatrix("ujmpmatrix", matrix);
256                    execute("boxplot(ujmpmatrix" + toString(format) + ")");
257            }
258    
259            public void closeLastFigure() throws Exception {
260                    execute("dev.off()");
261            }
262    
263    }