View Javadoc
1   /*
2    * Copyright 2017 Ange Optimization ApS
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  
18  package eu.simuline.octave.io.impl;
19  
20  import java.io.BufferedReader;
21  
22  import eu.simuline.octave.exception.OctaveParseException;
23  import eu.simuline.octave.io.OctaveIO;
24  import eu.simuline.octave.io.spi.OctaveDataReader;
25  import eu.simuline.octave.type.matrix.AbstractGenericMatrix;
26  
27  /**
28   * Common Reader class for matrices of primitive java types: 
29   * Boolean, Double, Integer.... 
30   *
31   * @param <T>
32   *    the type to be read in which has to extend {@link AbstractGenericMatrix}. 
33   */
34  abstract class AbstractPrimitiveMatrixReader
35      <T extends AbstractGenericMatrix<?,?>> 
36      extends OctaveDataReader {
37  
38      // **** to be eliminated: is in according writer 
39      protected static final String NDIMS    = "# ndims: ";
40      protected static final String NROWS    = "# rows: ";
41      protected static final String NCOLUMNS = "# columns: ";
42  
43  
44      abstract T createOctaveValue(int[] size);
45  
46      /**
47       * The matrix formats, e.g. <tt>matrix</tt> come in two variants: 
48       * after line with "type" the next line either starts with 
49       * <ul>
50       * <li><tt># ndims: </tt> specifying the number of dimensions 
51       * and in the next line the lengths in all these dimensions 
52       * and all the following lines the vectorized data, 
53       * each in a separate line. 
54       * This is read by {@link #readVectorizedMatrix(BufferedReader, String)}. 
55       * <li><tt># rows: </tt> specifying the number of rows 
56       * and <tt># columns: </tt> specifying the number of columns 
57       * in the next line (which works only for matrices, i.e. up to dimension 2) 
58       * and then for each row a line follows 
59       * each of which holds the entries separated by a blank. 
60       * This is read by {@link #read2dmatrix(BufferedReader, String)}. 
61       * </ul>
62       */
63      // **** caution: this distinction is valid only for floating point types. 
64      // others use vectorized format only 
65      // **** this may indicate inappropriate design. 
66      @Override
67      public T read(final BufferedReader reader) {
68          final String line = OctaveIO.readerReadLine(reader);
69          // 2d or 2d+?
70          if (line.startsWith(NROWS)) {
71  	    // this case does not occur for int types, 
72  	    // just for float (including complex) and bool 
73  	    // **** so this implementation may read things which do not occur 
74              return read2dmatrix(reader, line);
75          } else if (line.startsWith(NDIMS)) {
76  	    return readVectorizedMatrix(reader, line);
77          } else {
78              throw new OctaveParseException
79  		("Expected <" + NROWS + "> or <" + NDIMS + 
80  		 ">, but got <" + line + ">. ");
81          }
82      }
83  
84      private T readVectorizedMatrix(BufferedReader reader, 
85  				   String dimsLine) {
86  	int[] size = readSizeVectorizedMatrix(reader, dimsLine);
87   	T res = createOctaveValue(size);
88    	String line;
89  	// **** in the long run dataLength is not what we need 
90  	// active entries only 
91  	for (int idx = 0; idx < res.dataSize(); idx++) {
92              line = OctaveIO.readerReadLine(reader);
93   	    res.setPlain(line, idx);
94  	}
95          return res;
96      }
97  
98      /**
99       * Reads a line {@link #NDIMS num of dims} 
100      * followed by a line of dimensions: integers separated by blank 
101      * and returns an array with the according entries. 
102      * In particular the length is {@link #NDIMS num of dims}. 
103      */
104     private int[] readSizeVectorizedMatrix(BufferedReader reader, 
105 					   String ndimsLine) {
106         String line = ndimsLine;
107         if (!line.startsWith(NDIMS)) {
108             throw new OctaveParseException
109 		("Expected <" + NDIMS + ">, but got <" + line + ">. ");
110         }
111         final int ndims = Integer.parseInt(line.substring(NDIMS.length()));
112 
113         line = OctaveIO.readerReadLine(reader);
114         final String[] split = line.substring(1).split(" ");
115         if (split.length != ndims) {
116             throw new OctaveParseException
117 		("Expected <" + ndims + "> dimension, but got <" + 
118 		 split.length + "> (line was <" + line + ">). ");
119         }
120         final int[] size = new int[split.length];
121         for (int dim = 0; dim < split.length; dim++) {
122             size[dim] = Integer.parseInt(split[dim]);
123         }
124 	return size;
125     }
126 
127 
128     // maybe this just throws an exception because this case does not occur. 
129     private T read2dmatrix(BufferedReader reader, 
130 			   String rowsLine) {
131 	int[] size = readSize2dmatrix(reader, rowsLine);
132 	T res = createOctaveValue(size);
133 
134 	int rows    = size[0];
135 	int columns = size[1];
136 	String line;
137 
138 	for (int r = 1; r <= rows; ++r) {
139             line = OctaveIO.readerReadLine(reader);
140             final String[] split = line.split(" ");
141             if (split.length != columns + 1) {
142                 throw new OctaveParseException
143 		    ("Error in matrix-format: '" + line + "'");
144             }
145             for (int c = 1; c < split.length; c++) {
146 		res.setPlain(split[c], (r - 1) + (c - 1) * rows);
147             }
148         }
149         return res;
150     }
151 
152     /**
153      * Reads lines {@link #NROWS num of rows} and {@link #NCOLUMNS num of cols}
154      * and returns an array {nrows ncols}. 
155      */
156     protected int[] readSize2dmatrix(BufferedReader reader, 
157 				     String rowsLine) {
158         // # rows: 1
159         String line = rowsLine;
160         if (!line.startsWith(NROWS)) {
161             throw new OctaveParseException
162 		("Expected <" + NROWS + "> got <" + line + ">. ");
163         }
164         final int rows = Integer.parseInt(line.substring(NROWS.length()));
165         // # columns: 3
166         line = OctaveIO.readerReadLine(reader);
167         if (!line.startsWith(NCOLUMNS)) {
168             throw new OctaveParseException
169 		("Expected <" + NCOLUMNS + "> got <" + line + ">. ");
170         }
171         final int columns = Integer.parseInt(line.substring(NCOLUMNS.length()));
172         // 1 2 3
173         // final int[] size = new int[2];
174         // size[0] = rows;
175         // size[1] = columns;
176         return new int[] {rows, columns};
177     }
178 }