I have the following MATLAB function definition:
function dv = rc(t,v)
dv(1) = -0.1*v(1);
I'm trying to understand what it's doing. I can understand the expression and definition of the function, but why is there a (1) after dv and v? What does that do?
v(1) takes the first element of v if v is not a scalar (note that Matlab indices starts from 1 and not from 0).
The output of -0.1*v(1) is assigned to dv, specifically to the first element of dv, that is dv(1).
Note that since dv is not defined and is created by the assignment expression it is quite pointless to add the subscript (1) for this assignment.
Related
I'm going to perform some symbolic calculus for a project and I'm starting with something simple.
I'm ttrying to calculate the derivative of L function in respect to variable fi, but using the following code I get the error shown.
syms x(t) y(t) fi(t) m IR t;
L = 1/2*(m*(diff(x(t),t)^2+diff(y(t),t)^2) + IR*diff(fi(t),t)^2)
D1 = diff(L,diff(fi(t),t))
ERROR:
Error using sym/diff (line 70)
Second argument must be a variable or a nonnegative integer specifying the number of differentiations.
Could anyone tell me what's going on? Thanks.
[1]: https://i.stack.imgur.com/fTpEM.png
You have a nested diff in the second line. For the outer diff, the second argument cannot be the inner diff - it should be a variable or non-negative integer.
I have a use case as follows:
Inside F.m I have a function F that takes as its argument a 2 x 1 matrix x. F needs to matrix multiply the matrix kmat by x. kmat is a variable that is generated by a script.
So, what I did was set kmat to be global in the script:
global kmat;
kmat = rand(2);
In F.m:
function result = F(x)
global kmat;
result = kmat*x;
end
Then finally, in the script I have (x_0 has already been defined as an appropriate 2 x 1 matrix, and tstart and tend are positive integers):
xs = ode45(F, [tstart, tend], x_0);
However, this is causing the error:
Error using F (line 3)
Not enough input arguments.
Error in script (line 12)
xs = ode45(F, [tstart, tend], x_0);
What is going on here, and what can I do to fix it? Alternatively, what is the right way to pass kmat to F?
Firstly, the proper way to handle kmat is to make it an input argument to F.m
function result = F(x,kmat)
result = kmat*x;
end
Secondly, the input function to ode45 must be a function with inputs t and x (possibly vectors, t is the dependent variable and x is the dependent). Since your F function doesn't have t as an input argument, and you have an extra parameter kmat, you have to make a small anonymous function when you call ode45
ode45(#(t,x) F(x,kmat),[tstart tend],x_0)
If your derivative function was function result=derivative(t,x), then you simply do ode45(#derivative,[tstart tend],x_0) as Erik said.
I believe F in ode45(F,...) should be a function handle, i.e. #F. Also, you can have a look at this page of the MATLAB documentation for different methods to pass extra parameters to functions.
I have a following issue. I am trying to create a function handle, which is a vector. In particular, I have something like this
EQ0 = #(W) m1.^2*(exp(W))-m2.^2
where m1 and m2 are the vectors of the same dimension. So, for each m1(i) and m2(i) I want to have a handle W(i). I need it in order to find those W(i)'s in the next step using fsolve in something looking like this
n=size(m1)
x0 = zeros(n);
Wbar = fsolve(EQ0,x0)
I have tried using arrayfun, but received a following error
EQ0 = arrayfun( #(W) m1.^2*(exp(W))-m2.^2, m1=m1e, m2=m2e)
Error: The expression to the left of the equals sign is not a valid target for an assignment.
Another attempt in using arrayfun resulted in this (here I just used m1 and m2 vectors directly, not as an inputs like in previous case)
EQ0 = arrayfun( #(W) m1.^2*(exp(W))-m2.^2,:)
Undefined variable arrayfun.
I am clearly missing something. I have looked on some feeds on arrayfun but it looks like my problem is somewhat different.
Any advice is appreciated.
So if I understood you right you want to have for each m1(i) or m2(i) a seperate function handle EQ0(i) which can operate with an vector W in the following way EQ0(i) = #(W) m1(i)^2*(exp(W))-m2(i)^2. Is this correct? If so you can create a cell-array of the same dimension as m1 with a function handle in each dimension:
EQ0 = cell(size(m1));
for ii = 1:numel(m1)
EQ0(ii) = {#(W) m1(ii)^2*exp(W)-m2(ii)^2};
end
EDIT:
Another option could be:
EQ0 = #(W)arrayfun(#(Wel,m1el,m2el)m1el^2*exp(Wel)-m2el^2,W,m1,m2);
fsolve(EQ0, W_Values)
Here m1, m2 should be defined beforehand. Otherwise you have to add them as arguments of the first anonymous function.
So by calling arrayfun(#(Wel, m1el, m2el)..., W, m1, m2) you do your elementwise calculations for the entries in W, m1, m2 defined by the anonymous function handle you have passed in the first argument of arrayfun. But since you want to define your W differently each time, you make an anonymous function of that arrayfun command, which takes W as an argument.
Imagine I define two variables within a MuPad Notebook:
x:=2;
y:=5
For the product
z=x*y
I get displayed:
And if I use hold, I can get the expression:
z=hold(x*y)
But now I'd like to have both, the expression displayed and the result. The two options which appeared logical to me, do not worK:
z=hold(x*y);z
and
z=hold(x*y);eval(z);
How can I get displayed the expression AND the result?
If in two lines it would be alright, but I'd prefer in one line like:
z = x y = 10
I tried some combinations with print, expr2text, hold and _concat but couldn't find a convincing solution to get the desired result. But there is an explanation why the second line just returns z and not 10.
Assignment vs. Equation
z is the result in the second line because you didn't assign something to z yet. So the result says that z is z. In MuPad = is part of an expression. The assignment operator is := and therefore not the same as in Matlab. The only difference between them is the colon.
Writing an equation
For writing an equation, we use = as part of the expression. There is an equivalent function: _equal. So the following two lines generate the same result:
x+y = 2
_equal(x+y, 2)
Assign value to x
For an assignment we use := (in Matlab this would be only =). There is an equivalent function: _assign. So again, the following two lines generate the same result:
x := value
_assign(x, value)
Assign the equation x+y = 2 to eqn
Here we can clearly see the difference:
eqn := x+y = 2
_assign(eqn, _equal(x+y, 2))
As a toy example, I have a class that simply wraps a vector or matrix in an object and includes a timestamp of when it was created. I'm trying to overload subsref so that
() referencing works exactly as it does with the standard vector and matrix types
{} referencing works in exactly the same way as () referencing (nothing to do with cells in other words)
. referencing allows me to access the private properties of the object and other fields that aren't technically properties.
Code:
classdef TimeStampValue
properties (Access = private)
time;
values;
end
methods
%% Constructor
function x = TimeStampValue(values)
x.time = now();
x.values = values;
end
%% Subscripted reference
function x = subsref(B, S)
switch S.type
case '()'
v = builtin('subsref', B.values, S);
x = TimeStampValue(v);
case '{}'
S.type = '()';
v = builtin('subsref', B.values, S);
x = TimeStampValue(v);
case '.'
switch S.subs
case 'time'
x = B.time;
case 'values'
x = B.values;
case 'datestr'
x = datestr(B.time);
end
end
end
function disp(x)
fprintf('\t%d\n', x.time)
disp(x.values)
end
end
end
However brace {} referencing doesn't work. I run this code
clear all
x = TimeStampValue(magic(3));
x{1:2}
and I get this error:
Error using TimeStampValue/subsref
Too many output arguments.
Error in main (line 3)
x{1:2}
MException.last gives me this info:
identifier: 'MATLAB:maxlhs'
message: 'Too many output arguments.'
cause: {0x1 cell}
stack: [1x1 struct]
which isn't helpful because the only thing in the exception stack is the file containing three lines of code that I ran above.
I placed a breakpoint on the first line of the switch statement in subsref but MATLAB never reaches it.
Whats the deal here? Both () and . referencing work as you would expect, so why doesn't {} referencing work?
When overloading the curly braces {} to return a different number of output arguments than usual, it is also necessary to overload numel to return the intended number (1, in this case). UPDATE: As of R2015b, the new function numArgumentsFromSubscript was created to be overloaded instead of numel. The issue remains the same, but this function should be overloaded instead of numel as I describe in the original answer below. See also the page "Modify nargout and nargin for Indexing Methods". Excerpt:
When a class overloads numArgumentsFromSubscript, MATLAB calls this method instead of numel to compute the number of arguments expected for subsref nargout and subsasgn nargin.
If classes do not overload numArgumentsFromSubscript, MATLAB calls numel to compute the values of nargout or nargin.
More explanation of the underlying issue (need to specify number of output arguments) follows.
Original answer (use numArgumentsFromSubscript instead of numel for R2015b+)
To handle the possibility of a comma separated list of output arguments when indexing with curly braces, MATLAB calls numel to determine the number of output arguments from the size of the input indexes (according to this MathWorks answer). If the number of output arguments in the definition of overloaded subsref is inconsistent with (i.e. less than) the number provided by numel, you get the "Too many output arguments" error. As stated by MathWorks:
Therefore, to allow curly brace indexing into your object while returning a number of arguments INCONSISTENT with the size of the input, you will need to overload the NUMEL function inside your class directory.
Since x{1:2} normally provides two outputs (X{1},X{2}), the definition function x = subsref(B, S) is incompatible for this input. The solution is to include in the class a simple numel method to overload the builtin function, as follows:
function n = numel(varargin)
n = 1;
end
Now the {} indexing works as intended, mimicking ():
>> clear all % needed to reset the class definition
>> x = TimeStampValue(magic(3));
>> x(1:2)
ans =
7.355996e+05
8 3
>> x{1:2}
ans =
7.355996e+05
8 3
However, overloading curly braces in this manner is apparently a "specific type of code that we [MathWorks] did not expect customers to be writing". MathWorks recommends:
If you are designing your class to output only one argument, it is not recommended that you use curly brace indexing that requires you to overload NUMEL. Instead, it is recommended you use smooth brace () indexing.
UPDATE: Interestingly, the R2015b release notes state:
Before MATLAB release R2015b, MATLAB incorrectly computed the number of arguments expected for outputs from subsref and inputs to subsasgn for some indexing expressions that return or assign to a comma-separated list.
With release R2015b, MATLAB correctly computes the values of nargout and nargin according to the number of arguments required by the indexing expression.
So perhaps this is now fixed?
An alternative solution that comes to mind is to change function x = subsref(B, S) to function varargout = subsref(B, S) and adding varargout=cell(1,numel(B)); varargout{1} = x;. As Amro noted in comments, pre-allocating the cell is necessary to avoid an error about an unassigned argument.
I just ran into the same problem. What's even worse, is that the number of output arguments is enforced to be equal to what numel() returns not only for the curly braces {}, but also for the dot . operation.
This means that if numel() is overridden to return the usual prod(size(obj)), it becomes impossible to access any properties of the underlying object (such as x.time in the above example), as subsref() is then expected to return multiple outputs.
But if numel() just returns 1 instead, it does not match prod(size(obj)), which is what most code working with numeric values or based on reshape() expects. In fact, the MATLAB editor's balloon help immediately suggests that 'NUMEL(x) is usually faster than PROD(SIZE(x))', which suggest that they are equivalent, but apparently are not.
A possible solution would be to make numel() return prod(size(obj)) and write explicit getter/setter functions for all these properties, e.g.,
x.get_time()
in the example above. This seems to work, because method calls apparently get resolved before subsref() gets called. But then if one of the properties is a matrix it cannot be directly indexed any more because Matlab doesn't understand chained indexing, i.e., instead of writing
x.matrix(1,:)
one would have to write
m = x.get_matrix();
m(1,:)
which is ugly to say the least.
This is starting to get a bit frustrating. I still hope I've just overlooked something obvious, I can't believe that this is how it's supposed to work.
This solution seems to work in 2014b (but not entirely certain why)
classdef TestClass < handle
methods
function n = numel(~,varargin)
n = 1;
end
function varargout = subsref(input,S)
varargout = builtin('subsref',input,S);
end
function out = twoOutputs(~)
out = {}; out{1} = 2; out{2} = 3;
end
end
end
Then via the command window
>> testClass = TestClass();
>> [a,b] = testClass.twoOutouts()
a =
2
b =
3
I am working on a class to handle polynomials and polynomial matrices. I was having the same dificulty because I want different behaviors for the '.' indexing in the cases of scalar polynomials and polynomial matrices.
In my case I want P.coef to return a vector of coefficients if P is a scalar polynomial. If P is a polynomial matrix, P.coef must return a cell array of the same size of P, in which the cell {i,j} contains the coefficient vector of the polynomial P(i,j).
The problem appeared when P.coef was used with a matrix. My desired behavior returns only one object as an answer, but Matlab is expecting the function to return numel(P) objects.
I found a very simple solution. When declaring subsref, I used one mandatory output and a varargout:
function [R,varargout] = subsref(P,S)
The body of the function defines R as needed, according to my design. And at the very end of the function I added:
varargout(1:nargout-1) = cell(1,nargout-1);
To just return empty matrices as the extra outputs that Matlab wants.
This should create no problem if the function is always called with a single output argument, e.g., as in R = P.coef. If the function is called without assigning, the user will see numel(P)-1 empty matrices, which is really not a big deal. Anyway, the user is warned about this in the function help.