This project has moved. For the latest updates, please go here.

Help with Matrix XmlSerialization

Aug 5, 2013 at 6:02 PM
Edited Aug 5, 2013 at 6:04 PM
Hi,

I need to serialize a Matriz in order to store it in the database. Currently I'm trying to do this using XmlSerializer, but its throwing InvalidOperationException:
MathNet.Numerics.LinearAlgebra.Complex.DenseMatrix cannot be serialized because it does not have a parameterless constructor
Here's a piece of my code:
// MathNet version 2.6.0.29
// Framework 4.5
// Visual Studio 2012
// WCF

static void Main(string[] args)
{
    Type t = Type.GetType("MathNet.Numerics.LinearAlgebra.Complex.Matrix");
    var matrix = createMatrix();
    string xml = serializeToXML(matrix, t);
}

private Matrix createMatrix()
{
    DenseMatrix dm = new DenseMatrix(10,10);
    // populate cells ...
    return (Matrix)dm;
}

private string serializeToXML(object obj, Type type)
{

    using (MemoryStream ms = new MemoryStream())
    {

        object oConv; 

        XmlSerializer serializer = serializer = new XmlSerializer(type);

        #region 'cast from DenseMatrix to Matrix'
        MethodInfo castMethod = typeof(SerializationHelper).GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(type);
        oConv = castMethod.Invoke(null, new object[] { obj });
        #endregion 
        
        XmlWriterSettings xmlSettings = new XmlWriterSettings();
        xmlSettings.OmitXmlDeclaration = true;

        XmlWriter xml = XmlWriter.Create(ms, xmlSettings);

        try
        {
                        // this line throws the exception 
            serializer.Serialize(xml, oConv); 

            //also tried with direct cast like this:
            serializer.Serialize(xml, (Matrix)obj); 

        }
        catch (Exception)
        {
            throw;
        }

        byte[] bytes = ms.ToArray();
        string ret = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
        return ret;

    }

}

private static T Cast<T>(object o)
{
    return (T)o;
}
How can I do this serialization?


Thanks in regards!
Coordinator
Aug 7, 2013 at 10:18 AM
Hi,

Do you need the serialization to be in XML (for technical, standardization or whatever reasons), or would a simple text-based delimiter format like CSV or TSV work as well? If yes, I'd recommend to give our MathNet.Numerics.Data.Text library (NuGet package) a trial:
var m = DenseMatrix.CreateRandom(10, 10, Normal.WithMeanVariance(0.0, 1.0));

// serialize matrix to text:
string text;
var culture = CultureInfo.InvariantCulture;
using(var writer = new StringWriter(culture))
{
    DelimitedWriter.Write(m, writer, delimiter:"\t", formatProvider:culture);
    text = writer.ToString();
}

// deserialize text back to matrix:
Matrix<double> m2;
using (var reader = new StringReader(text))
{
    m2 = DelimitedReader.Read<double>(reader, delimiter: "\t", formatProvider:culture);
}
Thanks,
Christoph
Aug 7, 2013 at 2:52 PM
Edited Aug 7, 2013 at 4:51 PM
Hi Christoph!


Thanks for your response!

I do need to use XmlSerialization. I'll try to explain why.

I have a bunch of assembiles reflcted at runtime and its information stored in a table for late execution (using Invoke). Every parameter and every method result are XmlSerialized and stored because these assemblies can commuicate with each other. So, when I reflect the Matrix.Inverse() method, its return type (Mathnet...Matrix) is stored so that others assemblies can use it, deserializng its value to a dynamic type, like this:
// Conversions.dll
// Create a Matrix from an Excel file
// Method signature: Public Matrix XlsToMatrix(byte[] buffer)

// Metadata table (AssemblyMeta):
//    MethodName = "XlsToMatrix"
//    ReturnType = "MathNet...Matrix"
//    ParameterType = "System.Byte[]"
//    ParameterValue = [XML Column]
//    ReturnValue = [XML Column]

//------------------------------------------------------

AssemblyMeta meta = //[Read from database]

// type information is stored in the database
Type type = Type.GetType(meta.ParameterType);

// deserialize based on the type metadata
dynamic parameter = deserializeFromXML(meta.ParameterValue, type);

// reflect Conversion.dll and get its MethodInfo 

// this creates a Matrix from my Xls
dynamic result= methodInfo1.Invoke(null, new object[] { parameter }); 

// store the Matrix
meta.ReturnValue = serializeToXML(result, meta.ReturnType);
This complicated engine (its only a part of it) was designed to have NO knowledge of the types and completely relies on the metadata stored. Due to this architecture I cannot use different serialization methods for different types, because it would result in a type aware routine (switch(type) case 1: case 2: etc). Also it would cause a problem if I tried to check a type that doesn't exist in the 'logic machine', since my logic and execution runs in separate computers.

Sorry for this short (or crazy) explanation. The architecture complexity doesn't allow to write the hole logic.


Congratulations for this great library and once more, thanks for your help!

Kylderi
Coordinator
Aug 12, 2013 at 8:59 PM
Interesting setup!

Quick question: would it be an option to use a surrogate object, i.e. make the XlsToMatrix function return something like a SerializableMatrix<T> instead of a Matrix<T>?

SerializableMatrix would then have a Matrix property containing the actual matrix, and implement IXmlSerializable. This would be transparent to your serialization and invocation engine, but would mean that all functions used through this engine would pass around SerializableMatrix instead of Matrix.

Thanks,
Christoph
Aug 14, 2013 at 1:56 PM
Hi Christoph!

First, thank you for your kind response.

I've came to this same conclusion when I realized that the Matrix type uses two-dimensional arrays (Complex[,]), which are not supported by .Net for serialization. So I created a wrapper to hold the matrix data, so that there is no direct knowledge of the Matrix type.


Thanks for your attention and congrats for this great library!


Kylderi