Should the Symbolic Math Toolbox Enforce Assumptions on Assignment?

1 visualización (últimos 30 días)
Paul
Paul el 23 de Ag. de 2021
Comentada: Walter Roberson el 17 de Sept. de 2021
Consider the following:
syms a real
isAlways(in(a,'real'))
ans = logical
1
So far, so good. But
a = sym(2)*1i; % accepted w/o error or warning
Which then leads to some apparent contradictions
isAlways(in(a,'real'))
ans = logical
0
assumptions
ans = 

Respuestas (2)

Walter Roberson
Walter Roberson el 14 de Sept. de 2021
a = sym(2)*1i; % accepted w/o error or warning
As usual in MATLAB, if you are not using Simulink or MATLAB Coder, then the type of a variable is dynamic, and anything on the right side of an assignment completely overwrites whatever was in the left side of the assignment if it is an unindexed variable.
syms a real
That code is the same as
assignin('caller', 'a', sym('a', 'real'))
executed inside the syms function. So what is being assigned to a is the result of the sym function. MATLAB is not making a symbol-table entry marked as real: MATLAB is assigning an object to the MATLAB variable a
What properties does the object have? It turns out that the object does not store any information about assumptions. Instead, each symbolic object at the MATLAB level has amain properties: the s field which is a MATLAB character vector that is a reference to something that exists inside the Symbolic Engine.
When a + 1 is executed at the MATLAB level, the plus() operator is executed on the symbolic object (because the MATLAB level variable is a symbolic object), and the internal symbolic reference is looked up, and looks something like '_symans_[[32,0,59723]]' and that the 1 is converted to symbolic and has a similar symengine vector, and the two character vectors are passed to the symbolic engine. The symbolic engine looks them up in its internal tables and figures out how to add the two.
When you do
a = sym(2)*1i
then 2 is converted to symbolic number, creating a symbolic object with an s field like '_symans_[[32,0,59724]]' and the 1i is converted to symbolic number, getting something much the same in the s field, and the two _symans values are passed to the symbolic engine which does the appropriate work and returns a new character internal reference character vector that is stored in the s field of a symbolic object. Then, that symbolic object overwrites the MATLAB level object without ever "informing" the existing MATLAB level object, because in MATLAB assignment of an unindexed variable only involves the existing content to the extent that the existing content has its reference count reduced and might possibly be deleted.
When the sym('a','real') part was done, the name 'a' was passed to the symbolic engine to ask for its reference to symbolic engine variable named a and the assumption 'real' and the symbolic engine reference are sent to the symbolic engine, and the symbolic engine marks its internal symbolic engine variable a with the assumption -- the assumption makes no change at the MATLAB level (but might potentially return a different internal reference to be stored.) The MATLAB level has no idea what assumptions are stored against which expressions.
Remember that it is perfectly valid to do
syms a positive
a = a - 1
If you try to interpret this as saying that some kind of absolute variable named a exists at the MATLAB level, and should thereafter have all the properties from the assumptions, then you come to the conclusion that you must be asserting an identity, that a is a value such that a and a - 1 are the same value . You must, in other words, be asserting that a is one of -infinity, +infinity, or NaN ("undefined" as it is known to the symbolic engine.) But with the positivity constraint, you would have to be narrowing that down to say that a must be positive, so the combination would require that a is +infinity . This is, of course, as much incorrect at the MATLAB level as would be the case for saying that
a = 2
a = a - 1
"must" be asserting that a becomes the set of values such that a = 2 and a = 1 both hold -- that just isn't the case !
At the numeric level like that, when the a - 1 is seen in the second line, the current content of a is copied into the expression, and (content of a) - 1 is executed, and the result is stored over top of a .
Just so, symbolically, when you do
syms a positive
a = a - 1
then when you get to the a - 1 part, the current content of a is copied into the expression, with that being a reference to a symbolic engine variable, and then the - 1 part is executed in the symbolic level, and a new symbolic reference is returned, and that symbolic reference overwrites what is stored at the MATLAB level. The new symbolic engine reference returned after the a - 1 is to something that lives in the symbolic engine and has a reference to the symbolic engine variable a and a subtraction, but there is a distinction between the symbolic engine variable a and the MATLAB level variable a
Thus, symbolic variables have exactly the same semantics as numeric variables: content is copied in as needed on the right-hand side, new values are created as needed by the calculation on the right, and the new value overwrites the variable on the left side without the current content of the variable on the left side having anything to say about the matter.
... and as usual, you can force the current variable to be permitted to have a say in the matter by using
a(:) = a - 1
which would go through the subsasgn method associated with the existing a variable and allowing that method to do whatever is meaningful under the circumstances.
Allowing syms a postive to have influence on what happens with a = sym(2)*1i would require a complete change to MATLAB assignment semantics.
And you would have to figure out how to deal with syms a positive; a = a - 1 . For example syms a positive is the same as a = sym('a'); assume(a > 0) so to maintain those constraints in the face of a = a - 1 should the result be that a is still just a name, but that the assumption on a gets updated to (a > 1) and otherwise the -1 part should be discarded ????
  6 comentarios
Walter Roberson
Walter Roberson el 17 de Sept. de 2021
Let's rewrite very slightly:
syms a b
c = [a b]
c = 
for K = 1 : length(c)
result(K,1) = myfun(c(K));
end
result
result = 
function a = myfun(a)
a = a - 1;
end
Now, obviously if you pass in b to myfun, then the answer should be b-1: inside myfun, a is acting as a dummy variable that contains whatever value is passed in, and 1 is subtracted from that value and is returned.
Would it make sense to require that people routinely write
function varargout = myfun(varargin)
varargout{1} = varargin{1} - 1;
end
which has been carefully arranged to avoid using any variable names other than varargin and varargout since they can't know what the names of the symbolic variables being passed in will be, and you propose that there should be a link between symbolic names and MATLAB variable names ?
... did you know that in MATLAB, it is legal to
syms varargin varargout
myfun(varargin)
I am struggling to find a way to code a function for subtraction of 1 that is generalized for all symbolic variable names... it would be necessary to find a valid MATLAB variable name that is not a valid symbolic name, and I am having difficulty coming up with one.
Walter Roberson
Walter Roberson el 17 de Sept. de 2021
The current symbolic system is arguably broken
syms w positive
test_assume(w)
general assumptions
ans = 
assumptions about parameter
ans = 
is parameter always positive?
ans = logical
1
assumptions after syms w ans = Empty sym: 1-by-0 is parameter always positive now?
Warning: Unable to prove '0 < w'.
ans = logical
0
disp('assumptions after returning'); assumptions()
assumptions after returning ans = Empty sym: 1-by-0
function test_assume(x)
disp('general assumptions'); assumptions()
disp('assumptions about parameter'); assumptions(x)
disp('is parameter always positive?'); isAlways(x>0)
syms w
disp('assumptions after syms w'); assumptions
disp('is parameter always positive now?'); isAlways(x>0)
end
One could argue that inside the function, w should be a local variable, and therefore changing assumptions about w in the function should not be changing assumptions outside. But assumptions live inside the symbolic engine, and "syms w" talks about the symbolic variable named w that lives in the engine.
This does mean that symbolic variable names that you use inside functions are effectively global, and so you need to be very careful about them. But hardly anyone is... I know it is something I seldom think about myself when I am writing a function.

Iniciar sesión para comentar.


Tanmay Das
Tanmay Das el 13 de Sept. de 2021
Hi,
Symbolic objects and their assumptions are stored separately. When you set an assumption that a is real using
syms a real
you actually create a symbolic object a and the assumption that the object is real. The object is stored in the MATLAB workspace, and the assumption is stored in the symbolic engine. When you replace a symbolic object from the MATLAB workspace using
a = sym(2)*1i;
the assumption that a is real stays in the symbolic engine. If you declare a new symbolic variable a later using sym, it inherits the assumption that a is real instead of getting a default assumption. To clear the assumption, enter
syms a
Please refer to Use Assumptions on Symbolic Variables documention for further information.
However, in() function refers to a variable from the MATLAB workspace and hence has the latest status of its numeric type. So a possible workaround can be the following:
syms a real
isAlways(in(a,'real'))
syms a % to clear the earlier assumption
a = sym(2)*1i;
isAlways(in(a,'real'))
assumptions
  4 comentarios
Paul
Paul el 14 de Sept. de 2021
Editada: Paul el 14 de Sept. de 2021
FWIW, isreal not a documented function for sym objects. I think we are instead supposed to use
syms a real
isAlways(in(a,'real'))
ans = logical
1
In addition to the examples shown in my question and your comment, we get some other interesting effects:
syms f
f = a;
a = sym(2)*1i;
isAlways(in(f,'real'))
ans = logical
1
subs(f)
ans = 
Which I guess is pretty much the same result, just sort of one level removed from the underlying variable.
I also discovered this
clear all
assumptions
ans = Empty sym: 1-by-0
syms z
z = sym(2)*1i
z = 
assume(z,'real')
Warning: Ignored assumptions on constants.
assumptions
ans = Empty sym: 1-by-0
Interesting that the assumption can't apply to z if it has a value inconsistent with the assumption, but z can be assigned a value inconsistent with a previously defined assumption.
syms b
z = b
z = 
b
assume(z,'real')
assumptions
ans = 
An assumption on z is translated to an assumption on b, and the assumption on z is nowhere to be found.
Tanmay Das
Tanmay Das el 16 de Sept. de 2021
Regarding automatically updating assumptions, MATLAB does not inform when it deletes a MATLAB variable or assigns new values to it. So the assumptions, which are stored within the Symbolic engine, cannot be removed automatically. Furthermore, such a call into Symbolic may lead to slowdown MATLAB execution in general. Also, it is complicated to decide when to raise warning and when not to. Hence, it is recommended to use 'syms' to reinitialize the symbolic variable and reset all the assumptions associated with it.

Iniciar sesión para comentar.

Productos


Versión

R2021a

Community Treasure Hunt

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

Start Hunting!

Translated by