com.meliorbis.numerics.io.matlab.MatlabWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Numerics Show documentation
Show all versions of Numerics Show documentation
A library for working with large multi-dimensional arrays and the functions they represent
package com.meliorbis.numerics.io.matlab;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.PrimitiveIterator;
import com.jmatio.io.MatFileIncrementalWriter;
import com.jmatio.types.MLArray;
import com.jmatio.types.MLDouble;
import com.jmatio.types.MLEmptyArray;
import com.jmatio.types.MLInt32;
import com.jmatio.types.MLNumericArray;
import com.jmatio.types.MLStructure;
import com.meliorbis.numerics.generic.MultiDimensionalArray;
import com.meliorbis.numerics.generic.SettableIndexedIterator;
import com.meliorbis.numerics.generic.primitives.DoubleArray;
import com.meliorbis.numerics.io.NumericsWriter;
import com.meliorbis.utils.Utils;
/**
* Writes numerics arrays and structures of such arrays to .mat files
*
* NOTE: This relies on a patched version of JMatIO to write integer arrays
*
* @author Tobias Grasl
*/
public class MatlabWriter implements NumericsWriter
{
private final File _file;
private MatFileIncrementalWriter _matIOWriter;
MatlabWriter(File file_)
{
_file = file_;
}
private void init() throws IOException
{
if(_matIOWriter != null)
{
return;
}
// Ensure the .mat extension
File file = _file;
if(!file.getName().endsWith(".mat"))
{
file = new File(file.getAbsolutePath()+".mat");
}
_matIOWriter = new MatFileIncrementalWriter(file);
}
/**
* Write a single array with the given name into the output file
*
* @param name_ The name of the array in the output file
* @param array_ The array to write
*
* @throws IOException If an error occurs
*/
@Override
public void writeArray(String name_, MultiDimensionalArray extends Number, ?> array_) throws IOException
{
if(array_ == null) {
return;
}
init();
_matIOWriter.write(createMatLabArray(name_, array_));
}
/**
* Writes multiple named arrays to the output file
*
* @param arrays_ The map of arrays to write by the name to assign in the output file
*
* @throws IOException If an error occurs
*/
@Override
public void writeArrays(Map> arrays_) throws IOException
{
init();
Collection arrays = new ArrayList();
for(Map.Entry> namedArray : arrays_.entrySet())
{
arrays.add(createMatLabArray(namedArray.getKey(), namedArray.getValue()));
}
_matIOWriter.write(arrays);
}
/**
* Writes multiple named arrays to the output file
*
* @param name_ The name of the structure in the output file
* @param arrays_ The map of arrays to write by the name to assign in the structure
*
* @throws IOException If an error occurs
*/
@Override
public void writeStructure(String name_, Map> arrays_) throws IOException
{
init();
MLStructure structure = new MLStructure(name_, new int[]{1,1});
for(Map.Entry> namedArray : arrays_.entrySet())
{
if(namedArray.getValue() == null)
{
continue;
}
structure.setField(namedArray.getKey(), createMatLabArray(namedArray.getKey(), namedArray.getValue()));
}
_matIOWriter.write(structure);
}
/**
* Ends writing to this file and flushes the data
*
* @throws IOException If an error occurs
*/
@Override
public void close() throws IOException
{
if(_matIOWriter != null)
{
_matIOWriter.close();
}
}
@SuppressWarnings("unchecked")
private MLArray createMatLabArray(String name_, MultiDimensionalArray value_)
{
MLNumericArray matlabArray;
// If the array is empty just return an empty matlab array
if(value_.numberOfElements() == 0)
{
return new MLEmptyArray(name_);
}
/* Nasty, but arrange dimensions does not work on subarrays at present
*/
value_ = value_.copy();
// The default behaviour never returns null, so should be fine
int[] size = value_.size();
// The MATLABIO lib expects at least two dims
if(size.length == 1)
{
size = new int[] {size[0],1};
}
if(value_ instanceof DoubleArray>)
{
matlabArray = (MLNumericArray) new MLDouble(name_, size);
// Need to rearrange the dimensions because MATLAB uses them in opposite order
final PrimitiveIterator.OfDouble valIter =
(PrimitiveIterator.OfDouble) value_.
arrangeDimensions(Utils.sequence(value_.numberOfDimensions() - 1, -1)).iterator();
// Do our own counting because we need a linear index
int index = 0;
while (valIter.hasNext())
{
matlabArray.set((T) Double.valueOf(valIter.nextDouble()), index++);
}
}
else // By assumption, it is an integer array
{
matlabArray = (MLNumericArray) new MLInt32(name_, size);
// Need to rearrange the dimensions because MATLAB uses them in opposite order
final SettableIndexedIterator valIter =
value_.
arrangeDimensions(Utils.sequence(value_.numberOfDimensions() - 1, -1)).iterator();
// Do our own counting because we need a linear index
int index = 0;
while (valIter.hasNext())
{
matlabArray.set(valIter.next(), index++);
}
}
return matlabArray;
}
}