Question

I am looking for a way to list the differences between two .mat files, something that can be usefull for many people.

Though I searched everywhere I could think of, I have not found anything that meets my requirements:

  1. Pick 2 mat files
  2. Find the differences
  3. Save them properly

The closest I have come is visdiff. As long as I stay within matlab, it will allow me to browse the differences, but when I save the result it only shows me the top level.


Here is a simplified example of what my files typically look like:

a = 6;
b.c.d = 7;
b.c.e = 'x';
save f1
f = a;
clear a
b.c.e = 'y';
save f2
visdiff('f1.mat','f2.mat')

If I click here on b, I can find the difference. However if I run this and use 'file>save', I am not able to click on b. Thus I still don't know what has been changed.

Note: I don't have Simulink


Hence my question is:

How can I show all differences between 2 mat files to someone without Matlab


Here are the answers that I personally consider to be most suitable for different situations:

Was it helpful?

Solution 5

Simple general answer, without displaying value differences

Due to the insight I gained from the answers of @BHF, @Daniel R and @Dennis Jaheruddin, I have managed to find a simple scalable solution:

[fs1, fs2, er] = comp_struct(load('f1.mat'),load('f2.mat'))

Note that it works for .mat containing an arbritrary number of variables.

This uses the Compare Structures - File Exchange submission.

OTHER TIPS

Find all differences between mat files without MATLAB?

You can find the differences between HDF5 based .mat files with the HDF5 Tools.

Example

Let me shorten your MATLAB example and assume you create two mat files with

clear ; a = 6 ; b.c = 'hello' ; save -v7.3 f1
clear ; a = 7 ; b.e = 'world' ; save -v7.3 f2

Outside MATLAB use

h5ls -v -r f1.mat

to get a listing about the kind of data included f1.mat:

Opened "f1.mat" with sec2 driver.
/                        Group
    Location:  1:96
    Links:     1
/a                       Dataset {1/1, 1/1}
    Attribute: MATLAB_class scalar
        Type:      6-byte null-terminated ASCII string
        Data:  "double"
    Location:  1:2576
    Links:     1
    Storage:   8 logical bytes, 8 allocated bytes, 100.00% utilization
    Type:      native double
/b                       Group
    Attribute: MATLAB_class scalar
        Type:      6-byte null-terminated ASCII string
        Data:  "struct"
    Location:  1:800
    Links:     1
/b/c                     Dataset {5/5, 1/1}
    Attribute: H5PATH scalar
        Type:      2-byte null-terminated ASCII string
        Data:  "/b"
    Attribute: MATLAB_class scalar
        Type:      4-byte null-terminated ASCII string
        Data:  "char"
    Attribute: MATLAB_int_decode scalar
        Type:      native int
        Data:  2
    Location:  1:1832
    Links:     1
    Storage:   10 logical bytes, 10 allocated bytes, 100.00% utilization
    Type:      native unsigned short

Use of

h5ls -d -r f1.mat

returns the values of the stored data:

/                        Group
/a                       Dataset {1, 1}
    Data:
        (0,0) 6
/b                       Group
/b/c                     Dataset {5, 1}
    Data:
        (0,0) 104, 101, 108, 108, 111

The data 104, 101, 108, 108, 111 represents the word hello, which can be seen with

h5ls -d -r f1.mat | tail -1 | awk '{FS=",";printf("%c%c%c%c%c \n",$2,$3,$4,$5,$6)}'

You can get the same listing for f2.mat and compare the two outputs with the tool of your choice.

Comparison also works directly with HDF5 Tools. To compare the two numbers a from both files use

h5diff -r f1.mat f2.mat /a

which will show you the values and their difference

dataset: </a> and </a>
size:           [1x1]           [1x1]
position        a               a               difference          
------------------------------------------------------------
[ 0 0 ]          6               7               1              
1 differences found
attribute: <MATLAB_class of </a>> and <MATLAB_class of </a>>
0 differences found

Remarks

There are a few more commands and options in the HDF5 Tools, which may help to get your real problem solved.

Binary distributions are available for Linux and Windows from The HDF Group. For OS X you can get them installed via MacPorts. If needed there is also a GUI: HDFView.

If you have simulink you can use Simulink.saveVars to generate an m-file that upon execution creates the same variables in work space:

a = 6;
b.c.d = 7;
b.c.e = 'x';
Simulink.saveVars('f1');
f = a;
clear a
b.c.e = 'y';
Simulink.saveVars('f2');
visdiff('f1.m','f2.m')

as illustrated in this sctreenshot

enter image description here

Note that by default it limits the number of elements in arrays to 1000 and you can increase it to 10000. Arrays larger than that limit will be saved in a separate mat-file.

UPDATE: From R2014a a new function similar to Simulink.saveVars has been added to MATLAB. see matlab.io.saveVariablesToScript

This is only part of the answer, but maybe it helps.

You could use gencode, a Matlab function that generates Matlab code from a variable such that running the code reproduces the variable. You do this for all of the variables in each mat-file (takes some programming, but should be doable) and put the results in different .m-files.

Then you use a standard text comparison tool (maybe even visdiff) to compare the .m-files.

There are several good tools to compare XML-Files, this I would proceed this way:

  1. Download struct2xml.m
  2. Load both matfiles
  3. Export each with struct2xml
  4. compare, using XMLSpy or similar

Answer for small files, displaying all value differences

Based on the suggestion by @A. Donda I have tried to use gencode to create a variable for everything.

Though it works for my toy example, it is quite slow and tells me that I exceed the allowed amount of variables for my real .mat files.

Anyway, for those who are looking for something that works with small files, I will post this option:

wList=who;
for iLoop = 1:numel(wList)
    eval(['generated_' wList{iLoop} '= gencode(' wList{iLoop} ');'])
    for jLoop = 1:numel(eval(['generated_' wList{iLoop}]))
        eval(['generated_' wList{iLoop} '_' num2str(jLoop) '= generated_' wList{iLoop} '(' num2str(jLoop) ');' ])
    end
end

Though it may work, I don't feel like this is the best way to go.

General answer, without displaying value differences

Due to the insight I gained from the answers of @BHF and @Daniel R I have managed to find a reasonably scalable solution.

Step 1: Save all variables from each files as a single struct

This uses the Save workspace to struct - File Exchange submission.

Here are the steps to take assuming you want to compare f1.mat and f2.mat:

clear
load f1
myStruct1 = ws2struct;
save myStruct1 myStruct1 
clear
load f2
myStruct2 = ws2struct;
save myStruct2 myStruct2 
clear                    
load myStruct1
load myStruct2

Step 2: Compare the structs

This uses the Compare Structures - File Exchange submission

Given that you want to compare myStruct1 and myStruct2 you can simply call:

[fs1, fs2, er] = comp_struct(myStruct1,myStruct2)

I was positively surprised at how readable the list of differences in er is, here is the output for the example that was used in the question:

er =

's2 is missing field a'
's1(1).b(1).c(1).e and s2(1).b(1).c(1).e do not match'

Note that it will not show values, from a technical point of view it is probably not too hard to change the m file if value difference displays are desirable. However, especially if there are some big matrices I suppose this could result in problematic output.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top