Reversing the variable assignments in MATLAB - matlab

If I have a string "x1 = chyl_gi", where x1 and chyl_gi are both defined as symbolic variables, then the statement can be evaluated.
Typing in x1 will result in the value chyl_gi being returned.
Typing in chyl_gi will result in chyl_gi being returned.
How do I change the evaluation of "x1 = chyl_gi" so that typing in chyl_gi will result in returning x1? I can't change the order in how the variables are typed since I am working with a large text file in this format :
x1 = some var
x2 = another var
...

Now knowing your intended use, I recommend to use the subs function. Start parsing your text file to get the mapping:
syms x1 x2 chyl_gi chyl_gj a b c
mapping={x1,chyl_gi;x2,chyl_gj} %represents x1=chyl_gi and x2=chyl_gj;
And some example expression:
expr=x1+chyl_gi*(a+b+c);
Now you can simply use the subs function:
subs(expr,mapping,mapping(:,2:-1:1));
Which returns:
chyl_gi + x1*(a + b + c)
The advantage over the example in my comment above is, that you are really using the symbolic engine here.

Related

Can Julia macros be used to generate code based on specific function implementation?

I am fairly new to Julia and I am learning about metaprogramming.
I would like to write a macro that receive in input a function and returns another function based on the implementation details of its input.
For example given:
function f(x)
x + 100
end
function g(x)
f(x)*x
end
function h(x)
g(x)-0.5*f(x)
end
I would like to write a macro that returns something like that:
function h_traced(x)
f = x + 100
println("loc 1 x: ", x)
g = f * x
println("loc 2 x: ", x)
res = g - 0.5 * f
println("loc 3 x: ", x)
Now both code_lowered and code_typed seems to give me back the AST in the form of CodeInfo, however when I try to use it programmatically in my macro I get empty object.
macro myExpand(f)
body = code_lowered(f)
println("myExpand Body lenght: ",length(body))
end
called like this
#myExpand :(h)
however the same call outside the macro works ok.
code_lowered(h)
At last even the following return an empty CodeInfo.
macro myExpand(f)
body = code_lowered(Symbol("h"))
println("myExpand Body lenght: ",length(body))
end
This might be incredible trivial but I could not work out myseld why the h symbol does not resolve to the function defined. Am I missing something about the scope of symbols?
I find it useful to think about macros as a way to transform an input syntax into an output syntax.
So you could very well define a macro #my_macro such that
#my_macro function h(x)
g(x)-0.5*f(x)
end
would expand to something like
function h_traced(x)
println("entering function: x=", x)
g(x)-0.5*f(x)
end
But to such a macro, h is merely a name, an identifier (technically, a Symbol) that can be transformed into h_traced. h is not the function that is bound to this name (in the same way as x = 2 involves binding a name x, to an integer value 2, but x is not 2; x is merely a name that can be used to refer to 2). In contrast to this, when you call code_lowered(h), h gets evaluated first, and code_lowered is passed its value (which is a function) as argument.
Back to our macro: expanding to an expression that involves the definition of g and f goes way further than mere syntax transformations: we're leaving the purely syntactic domain, since such a transformation would need to "understand" that these are functions, look up their definitions and so on.
You are right to think about code_lowered and friends: this is IMO the adequate level of abstraction for what you're trying to achieve. You should probably look into tools like Cassette.jl or IRTools.jl. That being said, if you're still relatively new to Julia, you might want to get a bit more used to the language before delving too deeply into such topics.
You don't need a macro, you need a generated function. They can not only return code (Expr), but also IR (lowered code). Usually, for this kind of thing, people use Base.uncompressed_ast, not code_lowered. Both Cassette and IRTools simplify the implementation for you, in different ways.
The basic idea is:
Have a generated function that takes a function and its arguments
In that function, get the IR of that function, and modify it to your purposes
Return the new IR from the generated function. This will then be compiled and called on the original arguments.
A short demonstration with IRTools:
julia> IRTools.#dynamo function traced(args...)
ir = IRTools.IR(args...)
p = IRTools.Pipe(ir)
for (v, stmt) in p
IRTools.insertafter!(p, v, IRTools.xcall(println, "loc $v"))
end
return IRTools.finish(p)
end
julia> function h(x)
sin(x)-0.5*cos(x)
end
h (generic function with 1 method)
julia> #code_ir traced(h, 1)
1: (%1, %2)
%3 = Base.getfield(%2, 1)
%4 = Base.getfield(%2, 2)
%5 = Main.sin(%4)
%6 = (println)("loc %3")
%7 = Main.cos(%4)
%8 = (println)("loc %4")
%9 = 0.5 * %7
%10 = (println)("loc %5")
%11 = %5 - %9
%12 = (println)("loc %6")
return %11
julia> traced(h, 1)
loc %3
loc %4
loc %5
loc %6
0.5713198318738266
The rest is left as an exercise. The numbers of the variables are off, because they are, of course, shifted during the transformation. You'd have to add some bookkeeping for that, or use the substitute function on Pipe in some way (but I never quite understood it). If you need the name of the variables, you can get the IR with slots preserved by using a different method of the IR constructor.
(And now the advertisement: I have written something like this. It's currently quite inefficient, but you might get some ideas from it.)

sympy derivative with boolean

I am trying to take the derivative of a function including a boolean variable with sympy.
My expected result:
Two different derivatives, depending on the boolean being either True or False (i.e. 1 or 0).
Example:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
bo = sy.Function("bo")
fct1 = sy.Function("fct1")
fct2 = sy.Function("fct2")
FOC2 = sy.Function("FOC2")
y = 5
a = 2
b = 4
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
# the following gives the smaller positive intercept with the x-axis)
# this intercept is the threshold value for the boolean function, bo
min(sy.solve(fct1(x)-y, x))
def bo(x):
if fct1(x) <= y:
return 1
else:
return 0
def fct2(c, x):
return a + b*c + bo(x)*c
def FOC2(c, x):
return sy.diff(fct2(c, x), c)
print(FOC2(c, x))
The min-function after the comments shows me the threshold of x for bo being True or False would be 4.29..., thus positive and real.
Output:
TypeError: cannot determine truth value of Relation
I understand that the truth value depends on x, which is a symbol. Thus, without knowing x one cannot determine bo.
But how would I get my expected result, where bo is symbolic?
First off, I would advise you to carefully consider what is going on in your code the way it is pasted above. You first define a few sympy functions, e.g.
fct1 = sy.Function("fct1")
So after this, fct1 is an undefined sympy.Function - undefined in the sense that it is neither specified what its arguments are, nor what the function looks like.
However, then you define same-named functions explicitly, as in
def fct1(x):
return -0.004*x**2 + 0.25*x + 4
Note however, that at this point, fct1 ceases to be a sympy.Function, or any sympy object for that matter: you overwrite the old definition, and it is now just a regular python function!
This is also the reason that you get the error: when you call bo(x), python tries to evaluate
-0.004*x**2 + 0.25*x + 4 <= 5
and return a value according to your definition of bo(). But python does not know whether the above is true (or how to make that comparison), so it complains.
I would suggest 2 changes:
Instead of python functions, as in the code, you could simply use sympy expressions, e.g.
fct1 = -0.004*x**2 + 0.25*x + 4
To get the truth value of your condition, I would suggest to use the Heaviside function (wiki), which evaluates to 0 for a negative argument, and to 1 for positive. Its implementation in sympy is sympy.Heaviside.
Your code could then look as follows:
import sympy as sy
c, x = sy.symbols("c x", positive=True, real=True)
y = 5
a = 2
b = 4
fct1 = -0.004*x**2 + 0.25*x + 4
bo = sy.Heaviside(y - fct1)
fct2 = a + b*c + bo * c
FOC2 = sy.diff(fct2, c)
print(FOC2)
Two comments on the line
bo = sy.Heaviside(y - fct1)
(1) The current implementation does not evaluate sympy.Heaviside(0)by default; this is beacause there's differing definitions around (some define it to be 1, others 1/2). You'd want it to be 1, to be in accordance with the (weak) inequality in the OP. In sympy 1.1, this can be achieved by passing an additional argument to Heaviside, namely whatever you want Heaviside(0) to evaluate to:
bo = sy.Heaviside(y - fct1, 1)
This is not supported in older versions of sympy.
(2) You will get your FOC2, again involving a Heaviside term. What I like about this, is that you could keep working with this expression, say if you wanted to take a second derivative and so on. If, for the sake of readability, you would prefer a piecewise expression - no problem. Just replace the according line with
bo = sy.Heaviside(y - fct1)._eval_rewrite_as_Piecewise(y-fct1)
Which will translate to a piecewise function automatically. (note that under older versions, this automatically implicitly uses Heaviside(0) = 0.5 - best to use (1) and (2) together:
bo = sy.Heaviside(y - fct1, 1)._eval_rewrite_as_Piecewise(y-fct1)
Unfortunately, I don't have a working sympy 1.1 at my hands right now and can only test the old code.
One more noteconcerning sympy's piecewise functions: they are much more readable if using sympy's latex printing, by inserting
sy.init_printing()
early in the code.
(Disclaimer: I am by no means an expert in sympy, and there might be other, preferable solutions out there. Just trying to make a suggestion!)

How to write symbols to file in scilab

I'm working on symbolic toolkit. Trying to solve some equations and that's a long string of symbols such as x= a1+a2^3+b0*b1... upto 80,000(80k) characters.
So I needed to put that in file.
mputstr() ans other wrting functions are not working since they are symbols.
Error is thrown as: not a string or specified format.
Does any method can help to bring down the variable to file.
code is :
Syms aa ab ac
z=ab^6*ac^6*ad^3*ba^3*bg^3*bh^3+3*aa^4*ab^6*ac^6*ad^4*ba^4*bg^2*bh^2+3*aa^5*ab^6*ac^6*ad^5*ba^5*bg*bh+aa^6*ab^6*ac^6*ad^6*ba^6
mputstr({char(z)},fd)
>>error 10000
>>char: Wrong type for input argument: Cell expected.
at line 95 of function char called by :
mputstr(z,fd)
>> !--error 999
>mputstr: Wrong type for input argument #1: A string expected.
p=string(z)
mputstr(p,fd)
>>!--error 999
>mputstr: Wrong type for input argument #1: A string expected.
mfprintf("%s",z)
>> !--error 246
>>Function not defined for given argument type(s),
check arguments or define function %c_mfprintf for overloading. ..
Let's say you have a symbolic equation x:
syms a b c
x = a + b * c
Here, x denotes a symbolic variable, so you cannot directly write it to a file. You need to convert it to a character array first. So you should be using something like
fd = mopen( this_file, "wt" );
mputstr( char(x), fd );
mclose( fd );
I think that #bremen_matt's answer is the good one, but with a modification.
If your "Syms" variables are something complex so char() and string() cannot be used, why you are not creating your own conversion function?
Please, see below my modification of #bremen_matt example:
syms a b c
x = a + b * c
fd = mopen( this_file, "wt" );
mputstr( syms_to_string(x), fd );
mclose( fd );
The syms_to_string() is returning a string of the information that you would like to print of the symbol x, and same function could be used to print other symbols (e.g. a). Of course, the syms_to_string() function could be better defined using overloading.

Output argument "am" (and maybe others) not assigned during call to

I am trying to use this function in my m file but I get an error(mentioned in question). Everything seems correct and a, b and c are defined in my m file. Any thoughts?
Error:
Error in modal2 (line 8)
[v,an]=eig(a);
Output argument "am" (and maybe others) not assigned during call to "C:\Users\Cena\Desktop\Thesis\My Codes\SMC\modal2.m>modal2".
function [r,am,bm,cm] = modal2(a,b,c)
% this function determines the modal representation 2(am,bm,cm)
%given a generic state-space representation (a,b,c)
%and the transformation r to the modal representation
%such that am=inv(r)*a*r, bm=inv(r)*b and cm=c*r
%transformation to complex-diagonal form:
[v,an]=eig(a);
bn=inv(v)*b;
cn=c*v;
%transformation to modal form 2:
i = find(imag(diag(an))');
index = i(1:2:length(i));
j=sqrt(-1);
t = eye(length(an));
if isempty(index)
am=an;bm=bn;cm=cn;
else
for i=index
t(i:i+1,i:i+1)=[j 1;-j 1];
end
%Modal transformation
r=v*t;
end
The problem is likely in
if isempty(index)
am=an;bm=bn;cm=cn;
The assignment to those variables is only being done if the conditional passes. If it doesn't , there is no assignment.
You need to modify your code to assign to those variables under all conditions if they are going to be output arguments.

How do I use MATLAB's inputParser with optional string inputs? The documentation says "use a validation function" but it's unclear how to do that

I have a MATLAB file that contains a single top-level function, called sandbox. That function in turn contains two nested functions, mysum and myprod, which are identical in functionality and what parameters they allow except that one uses #sum internally and the other uses #prod internally. My goal is to create a wrapper function to use in both mysum and myprod that takes care of all the validation and input parsing. This function is called applyFunc.
Here's where it gets tricky. mysum and myprod come in two forms:
mysum(v) returns sum(v, 1).
mysum(v, 'imag') returns sum(v, 1) + 1i
Any other combinations of input should throw an error.
I'm having trouble using inputParser to parse these various combinations of input, specifically the optional string input. Here's the code:
function sandbox()
%% Data
v = [1 4; 3 3];
%% Calculations
s = mysum(v);
si = mysum(v, 'imag');
p = myprod(v);
pi = myprod(v, 'imag');
%% Accuracy tests
assert(isequal(s, [4 7]))
assert(isequal(si, [4+1i 7+1i]))
assert(isequal(p, [3 12]))
assert(isequal(pi, [3+1i 12+1i]))
function x = mysum(varargin)
x = applyFunc(#sum, varargin{:});
end
function x = myprod(varargin)
x = applyFunc(#prod, varargin{:});
end
end
function x = applyFunc(func, varargin)
p = inputParser();
p.addRequired('func', #(x) validateattributes(x, {'function_handle'}, {'scalar'}));
p.addRequired('v', #(x) validateattributes(x, {'double'}, {}, 'applyFunc:msg', 'v'));
p.addOptional('imag', '', #(x) validatestring(x, {'imag', ''})); % THIS LINE IS THE PROBLEM
p.parse(func, varargin{:});
f = p.Results.func;
v = p.Results.v;
strflag = p.Results.imag;
x = f(v);
if ~isempty(strflag)
validatestring(strflag, {'imag'});
x = x + 1i;
end
end
The line that's causing the problem is this one (as marked in the code above):
p.addOptional('imag', '', #(x) validatestring(x, {'imag', ''}));
The documentation for inputParser says that:
For optional string inputs, specify a validation function. Without a validation function, the input parser interprets valid string inputs as invalid parameter names and throws an error.
Unfortunately I don't have any idea how to do this. Is there something simple Im missing or what? If the 'imag' argument isn't passed at all (as in the assignment of s and p), the code works fine, but if I do pass it, I get this error:
Error using sandbox>applyFunc (line 32)
The value of 'imag' is invalid. It must satisfy the function:
#(x)validatestring(x,{'imag',''}).
Error in sandbox/mysum (line 18)
x = applyFunc(#sum, varargin{:});
Error in sandbox (line 7)
si = mysum(v, 'imag');
Any help?
The problem is that validatestring returns the matching string from the cell argument ({'imag',''}) rather than a Boolean indicating if it passes validation. Instead, use strcmp and any:
#(x) any(strcmp(x,{'imag', ''}))
Also, with validatestring, if the input string did not match either 'imag' or '' (actually just 'imag' since empty strings only match in R2014a+), it would throw an error rather than returning false so that the inputParser could return the appropriate error.
Another nice way to fix the problem is to change the syntax of applyFunc entirely so that instead of just 'imag' as an optional string input argument, use a Parameter-Value with 'imag' as the parameter and a validated boolean as the input.
The input definition suggested by Amro in the comments:
p.addParameter('imag', false, #(x)validateattributes(x, {'logical'}, {'scalar'}))
The usage:
mysum(x,'imag',true)
mysum(x) % default is equivalent to mysum(x,'imag',false)
This would simplify the rest of the code with p.Result.imag being a logical scalar. I would suggest:
x = f(v) + p.Result.imag*1i;
The problem is not inputParser, I think the issue is with validatestring.
1) First it does not match on empty strings:
>> x = ''
x =
''
>> validatestring(x, {'imag',''})
Expected input to match one of these strings:
imag,
The input did not match any of the valid strings.
Caused by:
Error using validatestring>checkString (line 85)
Expected input to be a row vector.
2) Second, if it successfully matches, it returns the resolved string (from one of the valid choice), instead of true/false. inputParser requires that the validation function either return a boolean, or nothing but throws error on failure.