조회 수: 5(최근 30일)

표시 이전 댓글

Consider the following:

syms a real

isAlways(in(a,'real'))

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'))

assumptions

Walter Roberson
2021년 9월 14일

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 ????

Walter Roberson
2021년 9월 17일 3:51

The current symbolic system is arguably broken

syms w positive

test_assume(w)

disp('assumptions after returning'); assumptions()

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.

Tanmay Das
2021년 9월 13일

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

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

Tanmay Das
2021년 9월 16일 6:55

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

Start Hunting!