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.InputStreamReader;
030    import java.io.OutputStreamWriter;
031    
032    import org.ujmp.core.Matrix;
033    import org.ujmp.core.enums.FileFormat;
034    
035    public class Octave {
036    
037            public static String[] SEARCH = new String[] {};
038    
039            static {
040                    try {
041                            SEARCH = new String[] { System.getProperty("Octave"), "/usr/bin/octave",
042                                            "/opt/octave/bin/octave" };
043                    } catch (Exception e) {
044                    }
045            }
046    
047            public static final int POLLINTERVAL = 50;
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 octaveProcess = null;
058    
059            private boolean running = false;
060    
061            private static Octave octave = null;
062    
063            private static String pathToOctave = null;
064    
065            public static synchronized Octave getInstance() throws Exception {
066                    if (octave == null) {
067                            octave = getInstance(findOctave());
068                    }
069                    return octave;
070            }
071    
072            public static synchronized Octave getInstance(String pathToOctave) throws Exception {
073                    if (octave == null) {
074                            octave = new Octave(pathToOctave);
075                    }
076                    return octave;
077            }
078    
079            private Octave(String pathToOctave) throws Exception {
080                    octaveProcess = Runtime.getRuntime().exec(pathToOctave);
081                    output = new BufferedWriter(new OutputStreamWriter(octaveProcess.getOutputStream()));
082                    input = new BufferedReader(new InputStreamReader(octaveProcess.getInputStream()));
083                    error = new BufferedReader(new InputStreamReader(octaveProcess.getErrorStream()));
084                    String startMessage = getFromOctave();
085                    if (startMessage != null && startMessage.length() > 0) {
086                            running = true;
087                            return;
088                    }
089                    throw new Exception("could not start Octave");
090            }
091    
092            private synchronized String getFromOctave() throws Exception {
093                    boolean colonSeen = false;
094                    boolean numberSeen = false;
095                    StringBuilder sb = new StringBuilder();
096    
097                    for (int i = 0; i < MAXPOLLS; i++) {
098                            if (!input.ready()) {
099                                    Thread.sleep(POLLINTERVAL);
100                            } else {
101                                    break;
102                            }
103                    }
104    
105                    while (input.ready()) {
106    
107                            char c = (char) input.read();
108                            sb.append(c);
109    
110                            if (numberSeen) {
111                                    if (c == '>') {
112                                            return sb.toString();
113                                    } else {
114                                            colonSeen = false;
115                                            numberSeen = false;
116                                    }
117                            } else if (colonSeen) {
118                                    if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5'
119                                                    || c == '6' || c == '7' || c == '8' || c == '9') {
120                                            numberSeen = true;
121                                    } else {
122                                            colonSeen = false;
123                                            numberSeen = false;
124                                    }
125                            } else {
126                                    if (c == ':') {
127                                            colonSeen = true;
128                                    }
129                            }
130                    }
131                    return sb.toString();
132            }
133    
134            public String execute(String command) throws Exception {
135                    sendToOctave(command);
136                    return getFromOctave();
137            }
138    
139            public synchronized void shutdown() throws Exception {
140                    sendToOctave("exit");
141                    octaveProcess.waitFor();
142                    output.close();
143                    input.close();
144            }
145    
146            private synchronized void sendToOctave(String command) throws Exception {
147                    if (!command.endsWith("\n")) {
148                            command = command + "\n";
149                    }
150                    output.write(command, 0, command.length());
151                    output.flush();
152            }
153    
154            public void setMatrix(String label, Matrix matrix) throws Exception {
155                    execute(label + "=" + matrix.exportToString(FileFormat.M));
156            }
157    
158            private static String findOctave() {
159                    if (pathToOctave == null) {
160                            File file = null;
161                            for (String s : SEARCH) {
162                                    if (s != null) {
163                                            file = new File(s);
164                                            if (file.exists()) {
165                                                    pathToOctave = file.getAbsolutePath();
166                                                    return pathToOctave;
167                                            }
168                                    }
169                            }
170                    }
171                    return pathToOctave;
172            }
173    
174            public Matrix getMatrix(String label) throws Exception {
175                    try {
176                            String rawRows = execute("fprintf(1,'%d\\n',size(" + label + ",1));");
177                            int rows = Integer.parseInt(rawRows.trim());
178                            String rawCols = execute("fprintf(1,'%d\\n',size(" + label + ",2));");
179                            int cols = Integer.parseInt(rawCols.trim());
180    
181                            String rawText = execute("fprintf(1,'%55.55f\\n'," + label + ")");
182                            String[] rawValues = rawText.split("\n");
183    
184                            Matrix matrix = Matrix.factory.zeros(rows, cols);
185    
186                            int i = 0;
187                            for (int c = 0; c < cols; c++) {
188                                    for (int r = 0; r < rows; r++) {
189                                            matrix.setAsDouble(Double.parseDouble(rawValues[i++]), r, c);
190                                    }
191                            }
192    
193                            return matrix;
194                    } catch (Exception e) {
195                            e.printStackTrace();
196                            return null;
197                    }
198            }
199    
200            public static boolean isAvailable() {
201                    return findOctave() != null;
202            }
203    
204            public void plot(Matrix matrix, String... format) throws Exception {
205                    setMatrix("ujmpmatrix", matrix);
206                    execute("figure;");
207                    execute("plot(ujmpmatrix" + toString(format) + ");");
208            }
209    
210            public void loglog(Matrix matrix, String... format) throws Exception {
211                    setMatrix("ujmpmatrix", matrix);
212                    execute("figure;");
213                    execute("loglog(ujmpmatrix" + toString(format) + ");");
214            }
215    
216            public void semilogx(Matrix matrix, String... format) throws Exception {
217                    setMatrix("ujmpmatrix", matrix);
218                    execute("figure;");
219                    execute("semilogx(ujmpmatrix" + toString(format) + ");");
220            }
221    
222            public void semilogy(Matrix matrix, String... format) throws Exception {
223                    setMatrix("ujmpmatrix", matrix);
224                    execute("figure;");
225                    execute("semilogy(ujmpmatrix" + toString(format) + ");");
226            }
227    
228            public void bar(Matrix matrix, String... format) throws Exception {
229                    setMatrix("ujmpmatrix", matrix);
230                    execute("figure;");
231                    execute("bar(ujmpmatrix" + toString(format) + ");");
232            }
233    
234            public void stairs(Matrix matrix, String... format) throws Exception {
235                    setMatrix("ujmpmatrix", matrix);
236                    execute("figure;");
237                    execute("stairs(ujmpmatrix" + toString(format) + ");");
238            }
239    
240            public void hist(Matrix matrix, String... format) throws Exception {
241                    setMatrix("ujmpmatrix", matrix);
242                    execute("figure;");
243                    execute("hist(ujmpmatrix" + toString(format) + ");");
244            }
245    
246            public void plot(Matrix x, Matrix y, String... format) throws Exception {
247                    setMatrix("ujmpmatrix_x", x);
248                    setMatrix("ujmpmatrix_y", y);
249                    execute("figure;");
250                    execute("plot(ujmpmatrix_x,ujmpmatrix_y" + toString(format) + ");");
251            }
252    
253            public void loglog(Matrix x, Matrix y, String... format) throws Exception {
254                    setMatrix("ujmpmatrix_x", x);
255                    setMatrix("ujmpmatrix_y", y);
256                    execute("figure;");
257                    execute("loglog(ujmpmatrix_x,ujmpmatrix_y" + toString(format) + ");");
258            }
259    
260            public void semilogx(Matrix x, Matrix y, String... format) throws Exception {
261                    setMatrix("ujmpmatrix_x", x);
262                    setMatrix("ujmpmatrix_y", y);
263                    execute("figure;");
264                    execute("semilogx(ujmpmatrix_x,ujmpmatrix_y" + toString(format) + ");");
265            }
266    
267            public void semilogy(Matrix x, Matrix y, String... format) throws Exception {
268                    setMatrix("ujmpmatrix_x", x);
269                    setMatrix("ujmpmatrix_y", y);
270                    execute("figure;");
271                    execute("semilogy(ujmpmatrix_x,ujmpmatrix_y" + toString(format) + ");");
272            }
273    
274            public void bar(Matrix x, Matrix y, String... format) throws Exception {
275                    setMatrix("ujmpmatrix_x", x);
276                    setMatrix("ujmpmatrix_y", y);
277                    execute("figure;");
278                    execute("bar(ujmpmatrix_x,ujmpmatrix_y" + toString(format) + ");");
279            }
280    
281            public void stairs(Matrix x, Matrix y, String... format) throws Exception {
282                    setMatrix("ujmpmatrix_x", x);
283                    setMatrix("ujmpmatrix_y", y);
284                    execute("figure;");
285                    execute("stairs(ujmpmatrix_x,ujmpmatrix_y" + toString(format) + ");");
286            }
287    
288            public void hist(Matrix x, Matrix y, String... format) throws Exception {
289                    setMatrix("ujmpmatrix_x", x);
290                    setMatrix("ujmpmatrix_y", y);
291                    execute("figure;");
292                    execute("hist(ujmpmatrix_x,ujmpmatrix_y" + toString(format) + ");");
293            }
294    
295            public void polar(Matrix theta, Matrix rho, String... format) throws Exception {
296                    setMatrix("ujmpmatrix_theta", theta);
297                    setMatrix("ujmpmatrix_rho", rho);
298                    execute("figure;");
299                    execute("hist(ujmpmatrix_theta,ujmpmatrix_rho" + toString(format) + ");");
300            }
301    
302            public void contour(Matrix z, Matrix n, Matrix x, Matrix y, String... format) throws Exception {
303                    setMatrix("ujmpmatrix_z", z);
304                    setMatrix("ujmpmatrix_n", n);
305                    setMatrix("ujmpmatrix_x", x);
306                    setMatrix("ujmpmatrix_y", y);
307                    execute("figure;");
308                    execute("contour(ujmpmatrix_z,ujmpmatrix_n,ujmpmatrix_x,ujmpmatrix_y" + toString(format)
309                                    + ");");
310            }
311    
312            public void mesh(Matrix x, Matrix y, Matrix z, String... format) throws Exception {
313                    setMatrix("ujmpmatrix_x", x);
314                    setMatrix("ujmpmatrix_y", y);
315                    setMatrix("ujmpmatrix_z", z);
316                    execute("figure;");
317                    execute("mesh(ujmpmatrix_x,ujmpmatrix_y,ujmpmatrix_z" + toString(format) + ");");
318            }
319    
320            public static String toString(String[] strings) {
321                    if (strings.length != 0) {
322                            return ",'" + strings[0] + "'";
323                    } else {
324                            return "";
325                    }
326            }
327    
328    }