001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.math.matrix;
031
032import java.io.DataInput;
033import java.io.DataOutput;
034import java.io.IOException;
035import java.io.PrintWriter;
036import java.lang.reflect.Field;
037import java.util.Scanner;
038
039import org.openimaj.io.ReadWriteable;
040
041import Jama.Matrix;
042
043/**
044 * A wrapper around a JAMA Matrix that is read-writeable by
045 * OpenIMAJ IOUtils.
046 * 
047 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
048 *
049 */
050public class ReadWriteableMatrix extends Matrix implements ReadWriteable {
051        private static final long serialVersionUID = 1L;
052
053        /**
054         * Construct a new matrix of zero size. Only for IOUtils use.
055         */
056        protected ReadWriteableMatrix() {
057                super(0, 0);
058        }
059        
060        /**
061         * Construct a matrix using the provided 2-D double array.
062         * The array is assigned internally and is not copied.
063         * 
064         * @param data the data
065         */
066        public ReadWriteableMatrix(double[][] data) {
067                super(data);
068        }
069
070        /**
071         * Construct a new matrix of the given size
072         * @param rows Number of rows
073         * @param cols Number of columns
074         */
075        public ReadWriteableMatrix(int rows, int cols) {
076                super(rows, cols);
077        }
078        
079        /**
080         * Construct a matrix using the provided matrix.
081         * The matrix data is assigned internally and is not copied.
082         * 
083         * @param data the data
084         */
085        public ReadWriteableMatrix(Matrix data) {
086                this(data.getArray());
087        }
088
089        @Override
090        public void readASCII(Scanner in) throws IOException {
091                final int rows = in.nextInt();
092                final int cols = in.nextInt();
093                
094                double[][] data = new double[rows][cols];
095                for (int r=0; r<rows; r++)
096                        for (int c=0; c<cols; c++)
097                                data[r][c] = in.nextDouble();
098                
099                setData(rows, cols, data);              
100        }
101
102        @Override
103        public String asciiHeader() {
104                return this.getClass().getName() + " ";
105        }
106
107        @Override
108        public void readBinary(DataInput in) throws IOException {
109                final int rows = in.readInt();
110                final int cols = in.readInt();
111                
112                double[][] data = new double[rows][cols];
113                for (int r=0; r<rows; r++)
114                        for (int c=0; c<cols; c++)
115                                data[r][c] = in.readDouble();
116                
117                setData(rows, cols, data);
118        }
119        
120        protected void setData(int m, int n, double[][] data) {
121                Class<Matrix> clz = Matrix.class;
122                try {
123                        Field mField = clz.getDeclaredField("m");
124                        mField.setAccessible(true);
125                        mField.setInt(this, m);
126                        
127                        Field nField = clz.getDeclaredField("n");
128                        nField.setAccessible(true);
129                        nField.setInt(this, n);
130                        
131                        Field AField = clz.getDeclaredField("A");
132                        AField.setAccessible(true);
133                        AField.set(this, data);
134                } catch (Exception e) {
135                        throw new RuntimeException(e);
136                }
137        }
138
139        @Override
140        public byte[] binaryHeader() {
141                return "RWMAT".getBytes();
142        }
143
144        @Override
145        public void writeASCII(PrintWriter out) throws IOException {
146                final int rows = this.getRowDimension();
147                final int cols = this.getColumnDimension();
148                final double[][] data = this.getArray(); 
149                
150                out.print(rows + " " + cols);
151                out.println();
152                
153                for (int r=0; r<rows; r++) {
154                        for (int c=0; c<cols; c++) {
155                                out.print(data[r][c] + " ");
156                        }
157                        out.println();
158                }
159        }
160
161        @Override
162        public void writeBinary(DataOutput out) throws IOException {
163                final int rows = this.getRowDimension();
164                final int cols = this.getColumnDimension();
165                final double[][] data = this.getArray(); 
166                
167                out.writeInt(rows);
168                out.writeInt(cols);
169                
170                for (int r=0; r<rows; r++)
171                        for (int c=0; c<cols; c++)
172                                out.writeDouble(data[r][c]);
173        }
174}