Undefined operator '-' for input arguments of type 'cell'.

Hello I am trying to optimize a function and I defined the objective function as follow:
Tp=Scope{1,1}.values(2:36,7);
T1= Scope{1,1}.values(2:36,9);
To= cell(35,1);
To{1}=70;
for i=2:36
To{i} = @(k) To{i-1} + (k)*(T1(i)- To{i-1} )
end
obj=(sum(Tp-To).^2)
end
Yet when running the function I keep getting the error Undefined operator '-' for input arguments of type 'cell'. Can you please help

 Accepted Answer

Tp = Scope{1,1}.values(2:36,7);
T1 = Scope{1,1}.values(2:36,9);
To = cell(35,1);
To{1} = @(k) 70;
for i=2:36
To{i} = @(k) To{i-1}(k) + (k)*(T1(i)- To{i-1}(k) );
end
obj = @(k) (sum(Tp-To(k)).^2);
This is not going to be efficient.

5 Comments

Hello Walter,
Do you have any idea why this is inefficient ? I just want to know why it takes so much time to give a response.
Kind regards,
Zaineb
Anonymous function calls are improving in efficiency compared to what they used to be, but they are still much less efficient than direct function calls or no function calls at all.
You are effectively doing recursion.
More efficient, if you have the symbolic toolbox:
syms k;
Tp = sym('Tp', [36, 1]);
T1 = sym('T1_', [36, 1]);
To = zeros(36, 1, 'sym');
tic
To(1) = 70;
for i=2:36; To(i) = simplify(To(i-1) + (k)*(T1(i)- To(i-1) )); end
toc
tic
general_obj = simplify( sum(Tp-To).^2 );
toc
I had to make some guesses here about what you wanted. You pull 35 values out of Scope{1,1}.values(2:36,9) to form T1, but you use up to T1 (36) . You define To up to entry 36, and subtract that from Tp which is of length 35, suggesting that you intend Tp to be 36 values instead of 35.
The process takes about 30 or so seconds, and leaves you with a general symbolic expression general_obj. You can then use the general symbolic expression with specific numeric coefficients:
particular_obj = simplify( subs(general_obj, {Tp, T1}, {Scope{1,1}.values(2:37,7), Scope{1,1}.values(2:37,9)} ) );
Notice the change to extract 36 values.
This method is much rapide then the other
I still have one question is how to find the optimum k minimizing that function. I have tried to insert Particular_obj in fminsearch/fmincon but it didnt work out , any idea please?
syms k;
Tp = sym('Tp', [36, 1]);
T1 = sym('T1_', [36, 1]);
To = zeros(36, 1, 'sym');
tic
To(1) = 70;
for i=2:36; To(i) = simplify(To(i-1) + (k)*(T1(i)- To(i-1) )); end
toc
tic
general_obj = simplify( sum(Tp-To).^2 );
toc
scope7 = randi([-20 20], 36, 1); %use your actual data instead
scope9 = randi([-20 20], 36, 1); %use your actual data instead
particular_obj = simplify( subs(general_obj, [Tp, T1], [scope7, scope9] ) );
dp = diff(particular_obj, k);
extrema_k = solve(dp, k);
d2p = diff(dp, k);
d2p_at_extrema = vpa(subs(d2p, extrema_k));
idx_of_mins = find(real(d2p_at_extrema) > 0 & imag(d2p_at_extrema) == 0);
k_that_give_minima = extrema_k(idx_of_mins);
The k that results will probably be expressed as an expression involving a root of a degree 35 polynomial. For example the result might be
root(z^35 - (3227*z^34)/90 + (28126*z^33)/45 - (635077*z^32)/90 + (869909*z^31)/15 - (33277391*z^30)/90 + (85636748*z^29)/45 - (731169439*z^28)/90 + (1319970097*z^27)/45 - (8179588387*z^26)/90 + (10995942521*z^25)/45 - (3450303739*z^24)/6 + (53667958351*z^23)/45 - (98616170809*z^22)/45 + (35828148439*z^21)/10 - (26141820801*z^20)/5 + (307189916182*z^19)/45 - (718894741631*z^18)/90 + (150917837051*z^17)/18 - (710737378307*z^16)/90 + (600510998233*z^15)/90 - (227349433612*z^14)/45 + (6845187087*z^13)/2 - (186250502473*z^12)/90 + (100186757903*z^11)/90 - (47741595209*z^10)/90 + 222721659*z^9 - (736455844*z^8)/9 + (1173520267*z^7)/45 - (106928494*z^6)/15 + (29646547*z^5)/18 - (28384297*z^4)/90 + (4382971*z^3)/90 - (104857*z^2)/18 + (4556*z)/9 - 2501/90, z, 13)
root(f(z),z) stands for the set of all z such that f(z) = 0 -- the roots of the function. root(f(z),z,N) stands for the N'th such root, using some undocumented ordering that appears to be related to phase angles somehow. This is the solution, which is to say that in this case the k at which the minima appeared cannot be expressed as an algebraic number, but is a particular root of a polynomial. If you want to know the approximate location, you can vpa() the value.

Sign in to comment.

More Answers (2)

Assuming that the error occurs on this line:
obj=(sum(Tp-To).^2)
then the issue is exactly as the error describes. Matlab does not know how to perform a subtraction on a cell array, as cells can contain anything from scalars to character strings. You need to specify which cell contents you want to subtract.

6 Comments

Also
To{i} = @(k) To{i-1} + (k)*(T1(i)- To{i-1} )
When i is 2, the To{i-1} refers to 70 which is ok, and a function handle gets stored in To{2}. But when i becomes 3 then the i-1 lookup pulls back the function handle and tries to add the function handle to something.
When you are trying to optimize a function then using lots of layers of anonymous functions will be inefficient. More efficient would typically be to use the symbolic toolbox to construct the expression and then use matlabFunction, possibly with the File option so that optimization is used.
You could also consider using memoization.
Thank You Mr Bob and You are very right Mr Walter when I try to call To{3}(1), I get Undefined operator '-' for input arguments of type 'function_handle' this time, any clue how to fix this ?
My best suggestion would be to solve the function within the loop, rather than leaving To{i} as a function handle.
Yes, great solution, yet this is only one part of the script, I am using Obj as the input argument of Fmincon which accept only handle functions :(
Are you trying to set To as a series of different equations then, and Obj is another series of combined equation? If so, then I would suggest trying to build these as strings, rather than functions, and then converting the completed string into a function. I'm not sure if it's possible to convert a string into a function, you would have to do some research on that, but I don't know that you can combine or reactively generate a function using another function.
str2fun() to convert character vector to anonymous function.

Sign in to comment.

syms k;
Tp = sym('Tp', [36, 1]);
T1 = sym('T1_', [36, 1]);
To = zeros(36, 1, 'sym');
tic
To(1) = 70;
for i=2:36; To(i) = simplify(To(i-1) + (k)*(T1(i)- To(i-1) )); end
toc
Elapsed time is 12.876785 seconds.
tic
general_obj = simplify( sum(Tp-To).^2 );
toc
Elapsed time is 1.880396 seconds.
scope7 = randi([-20 20], 36, 1); %use your actual data instead
scope9 = randi([-20 20], 36, 1); %use your actual data instead
particular_obj = simplify( subs(general_obj, [Tp, T1], [scope7, scope9] ) );
dp = diff(particular_obj, k);
extrema_k = solve(dp, k);
d2p = diff(dp, k);
d2p_at_extrema = vpa(subs(d2p, extrema_k));
idx_of_mins = find(real(d2p_at_extrema) > 0 & imag(d2p_at_extrema) == 0);
k_that_give_minima = extrema_k(idx_of_mins);

Community Treasure Hunt

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

Start Hunting!