Nesting parentheses issue: any workaround?

Greetings. I need to write a function based on a polynomial expression, but MatLab seems to dislike nested parentheses with depth greater than 32.
Since this function would serve as a parameter to a mixed integer nonlinear solver, i cannot use temporary variables since the solver would not recognize them ( i've already tried this approach ). Is there any way to "force" matlab, so that it wouldn't complain?
For instance eval, str2fun, or even m-files return the same error, that is matlab complaining because of nesting depth limit.
Thanks for your attention.
==========================================
Addendum: The question is nontrivial. I thank for your help but you are off target, sorry to point out that.
Hope this may help: let's say you have a variable x that can be expressed as
x(t+1) = x(t)*(polynomial expression here)
when you develop this function you obtain
x(t+1) = x(t)*(x(t-1)*(x(t-2)*(...)))+( remaining polynomial elements)
at this point however I DO NOT have to solve this function. I have to pass this function as a constraint to a solver. In other words I have to define something like
my_func = @(x)( x(t)*(x(t-1)*(x(t-2)*(...)))+( remaining polynomial elements))
where my_func is an argument of another function, thus I don't have to solve the function itself.
However matlab fails when the evaluating my_func. Also, since the solver actually parse the whole expression, i cannot define a sub function, since the solver would not know how to parse it.
Thanks again...

10 Kommentare

Daniel Shub
Daniel Shub am 28 Mai 2013
Can you give a complete non-working example. I am pretty sure when you create an anonymous function the entire workspace is encapsulated, so your solver should know about the "subfunctions".
All right... I usually generate the needed function as follows
=========== code snippet No 1 begins here ============
t_previous = num2str(1); for i =1:time_horizon
t_previous = [ '(' t_previous ')*(1 - x(' num2str(i) ')+' num2str(local_vec(i)) ')'];
end
constr = str2fun( [ '@(x)(' t_previous ')' ]);
=========== code snippet No 1 ends here ============
where time_horizon is a parameter concerning the number of time slot i have to consider.
if i provide a sub function, the previous code can be rewritten as
=========== code snippet No 2 begins here ============
func_handles = {}; j = 0;
t_previous = num2str(1); for i =1:time_horizon
if (mod(i,10) == 0) j = j+1;
func_handles{j} = str2fun( [ '@(x)(' t_previous ')' ]);;
t_previous = [ '( func_handles{' num2str(j) '}(x))*(1 - x(' num2str(i) ')+' num2str(local_vec(i)) ')'];
else
t_previous = [ '(' t_previous ')*(1 - x(' num2str(i) ')+' num2str(local_vec(i)) ')']; end
end
constr = str2fun( [ '@(x)(' t_previous ')' ]);
=========== code snippet No 2 ends here ============
clearly, as you stated, the solver knows about the "subfunctions" but, since they appear as operators, it is not able to parse them since it does not see the polynomial expression within them.
Also, if i provide the vector input, both the expression return the expected result, however the solver I am using is not able to handle them. Additionally, if i change solver, that is if I use the genetic algorithm solver within the global optimization toolbox, the constraint works just fine, but a deterministic solver such has SCIP ( through opti toolbox interface ) will not.
Daniel Shub
Daniel Shub am 28 Mai 2013
This is NOT a useful example. If you want useful help you need to provide simplified code that can be run in MATLAB that produces the error. The code you have provided is simplified enough, however, it cannot be run.
Sorry about that, it was not too clear to me what you meant by "non-working example" what i am doing is roughly this:
================= begin ==================================
string_sample = '(((((((((((((((((((((((((((((((((((((((((((((((((17)*(1-((225*x(145))/863.4962)-0.94713 )+(((225*x(145))/863.4962)*50)+0.94713*17)*(1-((225*x(146))/863.4962)-0.94713 )+(((225*x(146))/863.4962)*50)+0.94713*17)*(1-((225*x(147))/863.4962)-0.94713 )+(((225*x(147))/863.4962)*50)+0.94713*16)*(1-((225*x(148))/863.4962)-0.94713 )+(((225*x(148))/863.4962)*50)+0.94713*16)*(1-((225*x(149))/863.4962)-0.94713 )+(((225*x(149))/863.4962)*50)+0.94713*16)*(1-((225*x(150))/863.4962)-0.94713 )+(((225*x(150))/863.4962)*50)+0.94713*16)*(1-((225*x(151))/863.4962)-0.94713 )+(((225*x(151))/863.4962)*50)+0.94713*16)*(1-((225*x(152))/863.4962)-0.94713 )+(((225*x(152))/863.4962)*50)+0.94713*16)*(1-((225*x(153))/863.4962)-0.94713 )+(((225*x(153))/863.4962)*50)+0.94713*17)*(1-((225*x(154))/863.4962)-0.94713 )+(((225*x(154))/863.4962)*50)+0.94713*17)*(1-((225*x(155))/863.4962)-0.94713 )+(((225*x(155))/863.4962)*50)+0.94713*20)*(1-((225*x(156))/863.4962)-0.94713 )+(((225*x(156))/863.4962)*50)+0.94713*20)*(1-((225*x(157))/863.4962)-0.94713 )+(((225*x(157))/863.4962)*50)+0.94713*22)*(1-((225*x(158))/863.4962)-0.94713 )+(((225*x(158))/863.4962)*50)+0.94713*22)*(1-((225*x(159))/863.4962)-0.94713 )+(((225*x(159))/863.4962)*50)+0.94713*22)*(1-((225*x(160))/863.4962)-0.94713 )+(((225*x(160))/863.4962)*50)+0.94713*22)*(1-((225*x(161))/863.4962)-0.94713 )+(((225*x(161))/863.4962)*50)+0.94713*23)*(1-((225*x(162))/863.4962)-0.94713 )+(((225*x(162))/863.4962)*50)+0.94713*23)*(1-((225*x(163))/863.4962)-0.94713 )+(((225*x(163))/863.4962)*50)+0.94713*23)*(1-((225*x(164))/863.4962)-0.94713 )+(((225*x(164))/863.4962)*50)+0.94713*23)*(1-((225*x(165))/863.4962)-0.94713 )+(((225*x(165))/863.4962)*50)+0.94713*23)*(1-((225*x(166))/863.4962)-0.94713 )+(((225*x(166))/863.4962)*50)+0.94713*23)*(1-((225*x(167))/863.4962)-0.94713 )+(((225*x(167))/863.4962)*50)+0.94713*24)*(1-((225*x(168))/863.4962)-0.94713 )+(((225*x(168))/863.4962)*50)+0.94713*24)*(1-((225*x(169))/863.4962)-0.94713 )+(((225*x(169))/863.4962)*50)+0.94713*24)*(1-((225*x(170))/863.4962)-0.94713 )+(((225*x(170))/863.4962)*50)+0.94713*24)*(1-((225*x(171))/863.4962)-0.94713 )+(((225*x(171))/863.4962)*50)+0.94713*24)*(1-((225*x(172))/863.4962)-0.94713 )+(((225*x(172))/863.4962)*50)+0.94713*24)*(1-((225*x(173))/863.4962)-0.94713 )+(((225*x(173))/863.4962)*50)+0.94713*24)*(1-((225*x(174))/863.4962)-0.94713 )+(((225*x(174))/863.4962)*50)+0.94713*24)*(1-((225*x(175))/863.4962)-0.94713 )+(((225*x(175))/863.4962)*50)+0.94713*23)*(1-((225*x(176))/863.4962)-0.94713 )+(((225*x(176))/863.4962)*50)+0.94713*23)*(1-((225*x(177))/863.4962)-0.94713 )+(((225*x(177))/863.4962)*50)+0.94713*22)*(1-((225*x(178))/863.4962)-0.94713 )+(((225*x(178))/863.4962)*50)+0.94713*22)*(1-((225*x(179))/863.4962)-0.94713 )+(((225*x(179))/863.4962)*50)+0.94713*22)*(1-((225*x(180))/863.4962)-0.94713 )+(((225*x(180))/863.4962)*50)+0.94713*22)*(1-((225*x(181))/863.4962)-0.94713 )+(((225*x(181))/863.4962)*50)+0.94713*21)*(1-((225*x(182))/863.4962)-0.94713 )+(((225*x(182))/863.4962)*50)+0.94713*21)*(1-((225*x(183))/863.4962)-0.94713 )+(((225*x(183))/863.4962)*50)+0.94713*22)*(1-((225*x(184))/863.4962)-0.94713 )+(((225*x(184))/863.4962)*50)+0.94713*22)*(1-((225*x(185))/863.4962)-0.94713 )+(((225*x(185))/863.4962)*50)+0.94713*20)*(1-((225*x(186))/863.4962)-0.94713 )+(((225*x(186))/863.4962)*50)+0.94713*20)*(1-((225*x(187))/863.4962)-0.94713 )+(((225*x(187))/863.4962)*50)+0.94713*19)*(1-((225*x(188))/863.4962)-0.94713 )+(((225*x(188))/863.4962)*50)+0.94713*19)*(1-((225*x(189))/863.4962)-0.94713 )+(((225*x(189))/863.4962)*50)+0.94713*19)*(1-((225*x(190))/863.4962)-0.94713 )+(((225*x(190))/863.4962)*50)+0.94713*19)*(1-((225*x(191))/863.4962)-0.94713 )+(((225*x(191))/863.4962)*50)+0.94713*17)*(1-((225*x(192))/863.4962)-0.94713 )+(((225*x(192))/863.4962)*50)+(-28.8988))';
handle_fun = str2func( [ '@(x) ' string_sample ]);
=========================== end =========================
the string_sample is automatically generated by the system depending on the model setup.
this one run. i've just checked it...
thank you for your attention
Jan
Jan am 28 Mai 2013
Bearbeitet: Jan am 28 Mai 2013
Wow, this is such ugly. I cannot reconsider, why you want to use such a strange formulation. The author of the generator of this code should be blamed and forced to construct something more useful.
Note that subexpressions like (((225*x(175))/863.4962)*50) can be simplified to x(175)*13.0284302351302. Vectorizing will reduce the complexity also.
NotOfYourBusiness OrMaybeItIs
Bearbeitet: NotOfYourBusiness OrMaybeItIs am 28 Mai 2013
Guess what? I'm probably a psycho with too much free time in my hands. Or maybe you just don't have the slightest idea of what mixed integer nonlinear programming is, thus you just would not guess that those numbers may actually come from different parameters given at runtime...
Jan
Jan am 29 Mai 2013
Bearbeitet: Jan am 29 Mai 2013
Mixed integer nonlinear programming is no excuse for such an output, but a lack of algebraic methods for simplifications is.
Not only you are missing the point since the problem lies elsewhere, but also you are making assumptions based on a snippet of code, which is simply absurd.
Jan
Jan am 29 Mai 2013
Bearbeitet: Jan am 29 Mai 2013
Perhaps your question is still not clear. And remember, that it is the nature of a forum, that the contributors offer their thoughts and suggestions based on the snippets of code presented by the OPs. Therefore I cannot see something absurd here. This is your first question in this forum. Perhaps you are not familiar with the customs here.
You write "matlab fails when the evaluating my_func". This observation is surely correct. But what is your question then?
Daniel Shub
Daniel Shub am 29 Mai 2013
I am closing this question. It is clear that without a substantial edit to the question which provides the link to the solver (and ideally its documentation) as well as the inputs, expected output, and error messages such that a meaningful answer will not be possible. Further, NotOfYourBusinessOrMaybeItIs, I am a little concerned about your behavior. TMW does not employee people to answer questions on Answers, we are all volunteers. If you don't like the help you are getting here, please consider using TMW official technical assistance channels or a paid service. Please feel free to edit the question to provide the level of detail necessary for us to answer the question.

Antworten (8)

Jan
Jan am 28 Mai 2013

3 Stimmen

It is not only Matlab, but I dislike 32 nested parenthesis also. It is impossible to debug such monsters efficiently.
I cannot imagine a situation, where this is required. Using temporary array should be sufficient also and it does not waste computing time:
a = ((1 + 2) * 3);
% versus:
b = 1 + 2;
a = b * 3;
Daniel Shub
Daniel Shub am 28 Mai 2013

2 Stimmen

Based on some of your comments to the original question and answers, it seems the "solver" is a custom function that you (or someone else) wrote and not a standard MATLAB function or one available on the FEX. This solver requires an argument "handle_fun" that is in a very particular form such that it can parse the argument as a polynomial. You are then trying to use this function with an extremely large polynomial that exceeds the limit of MATLAB nesting.
There is no way to increase the maximum MATLAB nesting depth (although one could file an enhancement request). Assuming that when your polynomial is represented in the allowable form that minimizes the nesting depth you still exceed the maximum, you cannot use the solver as is. One possibility would be to modify the solver to take the argument in a different and more efficient form. If the code for the solver is not available, then you will need a different solver.
I would guess that any solver that requires arguments in such a crazy format likely is not well designed for the problem at hand.
Walter Roberson
Walter Roberson am 27 Mai 2013

0 Stimmen

Perhaps use polyval ?

1 Kommentar

Remember you can define utility functions. For example,
Q = @(x) roots([5*x exp(-tan(x)]);
P = @(x) (17 + 35 * sin(Q(x));
fzero(P, [-1 1])
Kwen
Kwen am 27 Mai 2013

0 Stimmen

Is there any way to use less parenthesis? 32 sets seems like a large amount-maybe look into how MATLAB uses BEDMAS to simplify.
Teja Muppirala
Teja Muppirala am 28 Mai 2013

0 Stimmen

I am in agreement with Jan. I cannot recall a single instance where I needed to use 32 parenthesis for anything. If you really need to do something like that, do it recursively, or with some other method.
In your case, I think it can be done quite simply
%%1. Your current method. (I think you meant STR2FUNC not STR2FUN)
t_previous = num2str(1);
time_horizon = 5;
local_vec = [4 -3 2 9 6]; % Just random numbers
for i =1:time_horizon
t_previous = [ '(' t_previous ')*(1 - x(' num2str(i) ')+' num2str(local_vec(i)) ')'];
end
constr = str2func( [ '@(x)(' t_previous ')' ])
%%2. The exact same thing in one line of readable, scalable code
constr2 = @(x) prod(1 - x + local_vec)
%%3. Confirm they are the same
for n = 1:10
x = randn(1,time_horizon)
constr(x)
constr2(x)
end

6 Kommentare

Your solution works to the extent that the polynomial can be expressed as a simple product. I think this is closer to the original code
t_previous = cell(time_horizon, 1);
t_previous{1} = @(x)(1 - x(1)+local_vec(1));
for i = 2:time_horizon
t_previous{i} = @(x)(t_previous{i-1}(x)*(1 - x(i)+local_vec(i)));
end
constr3 = t_previous{end};
Although it is not clear to me if that is the best way to go.
It seems to me that Teja, ( and Jan ) are missing the point here... It's not up to me if i want to do it in a way or another. As I've said I cannot do otherwise. The function is a parameter and it is meant to be parsed. Since the solver cannot recognize anything besides algebraic operators only a polynomial representation is allowed.
Jan
Jan am 28 Mai 2013
No, I do not think that we miss a point. There are always alternative approaches. Remember that the the Matlab interpreter (as other compilers also) let all parenthesis disappear, because there is no processor command, which is equivalent to parentheses.
You do not have to define the code as anonymous function. And when you use a function (file) instead or recursion, the problem with the deeply nesting vanishes easily.
Strangely enough, if I use a m-file instead, the problem represents itself. If you paste the ugly string as the main body of a function, you can experiment that for your self.
Also, in the specific case, the Opti Toolbox won't work if the parameter is not an anonymous function, since otherwise the function would ask for an argument.
Thus, trust me, you still miss the point, and that is, "is there a workaround"? Only two answers are possible: "there is" and "there is not". Sadly enough, your theoretical dissertation on coding aesthetics, based on hurried assumptions for what it counts, does not face the problem. Really.
Jan
Jan am 29 Mai 2013
If the algebraic methods to simplify the code are applied, the code looks more aesthetic and it can be processed by Matlab due to the reduction of parenthesis. Of course the 2nd part would be more important for you, but the strategy remains the same.
The Optimization Toolbox can work with function handles as well as with anonymous functions. Both get input arguments and if you have a specific problem with the function handles in optimization functions, please post the corresponding code and the error messages or what ever describes the problems clearly.
"Sadly enough"? Is this still friendly? Are you trying to blame me for not getting the answer you like?
Walter Roberson
Walter Roberson am 29 Mai 2013
Okay, then... "there is".
Unfortunately for you, your "only two answers are possible" does not allow for statement of what the workaround is.
Jan
Jan am 28 Mai 2013

0 Stimmen

Matlab 5.3 accepts more parenthesis as far as I remember. But there have been other drawbacks, e.g. no function handles. Anyway, modern Matlab interpreters do not accept deeply nested parenthesis. You have to find another solution. And when you insist on using the above monster, you have to solve it with another program.

0 Stimmen

The solver I use is SCIP http://scip.zib.de/ which usually runs under GAMS http://www.gams.com/ or AMPL http://www.ampl.com/
Simply put, I'm not so sure these software are not well designed...

4 Kommentare

Jan
Jan am 28 Mai 2013
But the problems caused by such ugly formatted results are obvious. Otherwise you would not have to read our geeky comments and suggestions.
But without kidding, I see the problem. I'm German and out language has the nice opportunity to attach an infinite number of clauses and inclusion, such that you find even poems, short stories and a book, which consist of only one extremely long sentence. Nevertheless, beside the syntactical correctness the power to transport information is limited for such monsters. I would not claim, that the language is not well designed...
Anyway, you get these strings in the shown format and need a solution. Actually the required algebraic conversions are trivial and it should be possible to let Maple or MuPad perform enough simplifications, although I do not know if they can produce the compact vector notation of Matlab. Unfortunately I haven't worked with these programs for about 20 years now, but hopefully other contributors have more experiences.
No. I do not need a solution to the strings. The strings are supposed to remain as they are, for a purpose for what it counts.
Also the ugly appearance of the strings is not an issue. Not to me, nor to MatLab. Only the number of iteration used when generating the string is a problem, in fact Matlab starts to complain when its number exceed 32, non earlier.
All I need a solution to the Matlab complaining. Nothing more. Nothing less.
For instance Matlab should only pass the functions generated from the strings over to the solver, without caring on their meaning. But it does not.
In conclusion, you still miss the point. I'm not here for a chat on theoretical aspects of programming. If I was I would have come here at the beginning of my project, asking you an opinion on how to implement the work I'm doing.
For MathWorks' sake, please, avoid wasting customer's time... Thanks.
Jan
Jan am 29 Mai 2013
You want Matlab to perform something, which it is not designed for. When it cannot handle 32 nested parenthesis, you have to reduce the number. There is no magic flag, which increases the number of accepted parenthesis to a larger number.
You have pointed out already, that I'm missing the point. But what is your point, or better: what is your question? At least this is not a useful explanation: "Only the number of iteration used when generating the string is a problem" (I'm not sure what this means) and "matlab fails when the evaluating my_func" (ok, but this is a limitation of the design of Matlab - the forum cannot create a new version for your needs).
It could be possible, it is at least worth to be considered, that you do not get my point. I have the impression that you get emotional. Perhaps it helps you to know, that I'm here to solve Matlab problems. And if the problems are a little abstract, my answers are also. Ok?
Perhaps it would have been a good idea to ask the forum for the design of your program. But now it looks like you have driven into a blind end and think that is the fault of Matlab or the dull contributors in the forum, which cannot or do not give the answer you like.
per isakson
per isakson am 29 Mai 2013
For The MathWorks' sake ask their tech support for help. Obviously, we cannot help you.
Jan
Jan am 29 Mai 2013
Bearbeitet: Jan am 29 Mai 2013

0 Stimmen

To summarize my comments, which might be better in the answers section:
  1. Modern Matlab versions cannot handle more than 32 nested parenthesis. (You have found out this fact already)
  2. There is no workaround like a magic flag.
  3. A promising workaround is a redesign of your program. The created function can get nicer and simultaneously contain less nested expressions (and from my point of view, this means the same).
  4. You could try to let a computer algebra program perform the simplifications of the string before you apply STR2FUNC.
  5. If the solver does not accept function handles, perhaps the solver is not sufficient for what you want to do. But when it accepts anonymous functions, function handles are expected to work also.

Diese Frage ist geschlossen.

Community Treasure Hunt

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

Start Hunting!

Translated by