How to save a symbolic equation in a txt file?

I have a complex system of equations for the dynamics of a rigid body.
I want to store the resultant matrix in a txt file (or any other format that works well) so that I do not have to compute the symbolic expression inside a numerical solver.
How do I store it in a proper format and then how do I read it?

 Akzeptierte Antwort

Walter Roberson
Walter Roberson am 28 Mär. 2020

3 Stimmen

save('test.mat', 'A', 'a', 'b', 'c');
When you use
syms a
that is equivalent to
a = sym('a');
That calls into the symbolic engine to create a variable named a inside the symbolic engine, and return a reference to the variable. The reference will look something like '_symans_[[32,0,43]]' . That reference will be recorded inside a symbolic object and that object will be assigned to the variable named a at the MATLAB level. The MATLAB level variable named a is not itself something that lives inside the symbolic engine; it is just that '_symans_[[32,0,43]]' that was returned by the symbolic engine.
When symbolic operations are done on a, such as a+1 then the symbolic toolbox pulls out that internal reference _symans_[[32,0,43]] and passes that to the symbolic engine along with the '+1', so it would look something like
evalin(symengine, '_symans_[[32,0,43]]+1')
The symbolic engine looks up _symans_[[32,0,43]] in its tables, find the appropriate expression, does the calculation, and returns a reference to a new symbolic variable, such as '_symans_[[32,0,89]]'
When you construct A from [a b c] then what would happen would be that the symbolic engine would get passed something like
evalin(symengine, '_DOM_LIST([_symans_[[32,0,43]], _symans_[[32,0,89], _symans_[[-7,5,18]]])')
and it would construct the list and return yet another internal reference. Notice that it is not getting passed the names of MATLAB variables, only references to expressions that live in the symbolic engine. A would become a symbolic reference to content that MATLAB does not know about until it asks the symbolic engine for the content.
When you save() A, MATLAB would ask the symbolic engine to return a parse-tree of symbolic expressions that can later be executed inside the symbolic engine to re-create the expression. It does not just ask for a printable version of the expression because in symbolic expressions, what appears to be the same variable is not always the same variable, especially when you get into nested structures.
Then you clear the variables. When you do so, the MATLAB level variables a, b, c stop existing, and information connecting them to (say) _symans_[[32,0,43]] is gone. You load symbolic variable A and it recreates references inside the symbolic engine to symbolic variables a, b, c that live in the symbolic engine, and A would get a new _symans reference. But that does not recreate the connection between the MATLAB variables a, b, c and the symbolic engine.
The situation is much like if you had done
a = 1; b = 2; c = 3;
A = [a, b, c];
and saved A and cleared the workspace and restored A, and if you then expected that a and b and c were also automatically restored, on the basis that A referred to them. No, A does not refer to them, MATLAB copied their values into A and throws away the information about where it got the values. Likewise when you have symbolic variables installed, MATLAB copies their values -- but the values of symbolic variables are the references into the symbolic engine, not the connection between the local variables of that name and whatever is inside the symbolic engine.
Consider for example if you had done
syms a b c
A = [a*2;b*0;c+5];
save('test.mat', 'A');
then upon the load() would you expect a and b and c to be restored? A doesn't even contain a reference to symbolic engine variable b -- the b*0 is 0 before you even get around to constructing A. MATLAB does not take a record of the variable names used to construct an expression and the expression that was used, only a copy of the evaluated values.

6 Kommentare

Thanks for providing a detailed analysis. But I am a bit confused because your analysis seems to suggest that once we run clear and load the matrix again from the mat file, the reference to the symengine variables corresponding to a, b, and c will be lost. But from the following example, it appears that we can recreate the reference to the symengine variables again
syms a b c
A = [a*2;b*0;c+5];
save('test.mat', 'A');
clear
load('test.mat')
syms a b c
x = A(1)^2;
subs(A.^2, [a b c], [2 2 2])
Result:
ans =
16
0
49
The elements inside A were a reference to the initial a, b, and c (defined on the first line of the script). After I run clear, the reference is lost. So when I again run syms a b c the new MATLAB variables should point to a different location inside the symengine. But the above example shows that symengine recognizes them as the same symbolic variables. I guess there is some connection between MATLAB level variable name and its reference inside the symengine: a symbolic variable named 'a' might always point to the same location inside the symengine. Of course, the symengine needs to recognize the difference between the workspaces; variable 'a' in the base workspace and a function workspace should not be the same. This is just my speculation. I am not sure how it is actually implemented.
Interesting test. Unfortunately success depends upon MATLAB release and exact variable names used.
R2015sp1:
>> struct(sym('a'))
s: 'a'
cplxunit: '1i'
>> struct(sym('alpha'))
s: 'alpha'
cplxunit: '1i'
>> struct(sym('beta'))
s: 'beta_Var'
cplxunit: '1i'
>> struct(sym(pi))
s: '_symans_32_0_135'
cplxunit: '1i'
>> struct(sym('pi'))
s: 'pi'
cplxunit: '1i'
Of the variables I tested, beta and gamma had representations with _Var . Notice pi has two different representations, but sym(pi)-sym('pi') will indeed give 0.
R2020a:
>> struct(sym('a'))
struct with fields:
s: 'a'
mathmlOutput: []
Digits: 32
>> struct(sym('alpha'))
struct with fields:
s: '_symans_[[32,0,45846]]'
mathmlOutput: []
Digits: 32
>> struct(sym('beta'))
struct with fields:
s: '_symans_[[32,0,45847]]'
mathmlOutput: []
Digits: 32
Of the variables I tested, only the single-letter ones used the same internal name. The numbers 45846, 45847 were being generated in sequence as I tried random names.
The following shows that the symengine references might not be as necessary for the symbolic variables as one might think. MATLAB level variable names have some level of influence on the outcome
>> syms a1 a2
>> A = [a1 a2];
>> struct(a1)
struct with fields:
s: '_symans_[[32,0,29302]]'
mathmlOutput: []
Digits: 32
>> struct(a2)
struct with fields:
s: '_symans_[[32,0,29306]]'
mathmlOutput: []
Digits: 32
>> save('test.mat', 'A', 'a1', 'a2');
>> clear
>> load('test.mat');
>> struct(a1)
struct with fields:
s: '_symans_[[32,0,29359]]'
mathmlOutput: []
Digits: 32
>> struct(a2)
struct with fields:
s: '_symans_[[32,0,29382]]'
mathmlOutput: []
Digits: 32
>> struct(A(1))
struct with fields:
s: '_symans_[[32,0,29416]]'
mathmlOutput: []
Digits: 32
>> struct(A(2))
struct with fields:
s: '_symans_[[32,0,29417]]'
mathmlOutput: []
Digits: 32
>> subs(A.^2, [a1 a2], [3 2])
ans =
[ 9, 4]
This example shows that the symengine reference of a1 and a2 before and after the clear are different. Even the reference of A(1) and A(2) matches neither of the other. Still, MATLAB recognizes them as the same symbolic variables.
This was a very interesting discussion. Now I've experience what you're saying. But it only happens when there are less variables. I tried it with the example I mentioned and it worked.
So, I went on and tried it with my dynamics state equation and it is a 12 x 12 matrix with around 20 variables and it does load the symbolic expression succesfully in the workspace.
But, when I try to use matlabFunction(), it shows me an error. Any idea, Walter?
f_x is my symbolic expression that I succesfully loaded from file after saving and clearing.
dfdx = matlabFunction(f_x)
The result is:
Error using sym/matlabFunction>checkVars (line 223)
Variable names must be valid MATLAB variable names.
Error in sym/matlabFunction (line 158)
vars = checkVars(funvars,opts);
Should I be saving all my variables with my expression to avoid this? (as below)
save('test.mat', 'A', 'a', 'b', 'c');
Ameer Hamza
Ameer Hamza am 29 Mär. 2020
Anirudh, can you show a simple example to recreate the error with the matlabFunction? Also can you specify your MATLAB release?

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (2)

Ameer Hamza
Ameer Hamza am 28 Mär. 2020
Bearbeitet: Ameer Hamza am 28 Mär. 2020

1 Stimme

You can save the variables in a .mat file which is the MATLAB's own file type to save data.
save('filename', 'variableName');
Then you can load it back to the workspace
load('filename')

4 Kommentare

Can I store the symbolic matrix as it is? And when I read it, will it still be a symbolic expression?
Ameer Hamza
Ameer Hamza am 28 Mär. 2020
Yes, it will also work for symbolic variables. You just need to load the file and it will appear in the workspace as a sym.
I can load it and find it the workspace as type sym. But in a new program, the variables/symbols have been cleared.
So now how do I substitute numeric values into those symbols which make up the original expression?
syms a b c
A = [a;b;c];
save('test.mat', 'A');
clear;
load('test.mat')
subs(A,a,2)
Error: Undefined function or variable 'a'.
Thank you so much for your help.

Melden Sie sich an, um zu kommentieren.

Walter Roberson
Walter Roberson am 28 Mär. 2020

1 Stimme

If you plan to use the expression inside a numeric solver, you should use matlabFunction(), which has the advantage of converting symbolic expressions into numeric ones.
If this involves differential equations that you are passing through one of the ode* functions, then you should see odeFunction(), and be sure to read the first example there, as it has valuable information on suggested workflow for converting symbolic ode into numeric ones.

6 Kommentare

I usually use 'subs' for substituting the values and 'double' for converting the symbolic expression to double.
How can I substitute values of the symbolic variables using matlabFunction()?
Oh, I get it now. Thanks a lot.
I have an issue where the results of the solver is in the form of rootsOf() and also have variables associated with it. matlabFunction() throws an error
"Code generation failed due to unexpected object of type 'RootOf'."
Do you any other function or method with which I can save the results?
What is the maximum degree of the variable being solved for in the RootOf? And are these the results of solve() or dsolve()? Also which MATLAB version are you using?
If they are from solve and maximum degree 4 then you can pass the MaxDegree option but the formula gets very long.
If they are from dsolve then you are not giving a chance to pass MaxDegree.
In r2019b new tools became available to post process symbolic expressions. For RootOf polynomial it becomes more plausible to create new code. But dsolve tends to use RootOf() in a different context that is more difficult to deal with.
In particular, dsolve() tends to generate situations involving the sum of an expression with a variable being all of the possible roots of some expression; it uses RootOf to do that. But the RootOf that it generates are not necessarily roots of a polynomial, and can be nonlinear, and finding all of the roots (including the complex ones) of an arbitrary expression can be difficult.
Sagar Chirania
Sagar Chirania am 20 Apr. 2020
Bearbeitet: Sagar Chirania am 20 Apr. 2020
I am not dealing with differential equations. These are the results of solve(). The maximum degree is 8.
I am solving a set of 6 coordinate geometric equations. There is an unknown symbolic variable t in the solution that changes depending on position of particular object.The matlabFunction(), as I told throws the error and I cannot store the solution too, as when I load it again, there is no reference to t.
Do you have any method in particular or would I have to solve it for t always?

Melden Sie sich an, um zu kommentieren.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by