Optimization with loops Error in optim.problemdef.OptimizationProblem/solve
Show older comments
Q1. I want to perform certain operation on two large column vectors and calculate a cumulative sum in a certain order without using loops. For simplicity assume that I have two column vectors:
A=[1;3;5;7] and B = [10;12;14;19]
and I want to find a vector C = [1;1*10+3;1*10+3; (1*10+3)*12+5; ((1*10+3)*12+5)*14+7 ] = [1;13;161;2261]
What will be the MATLAB code to calculate vector C in MATLAB without using loops?
Q2. I have provided my code below and I have used the helpful suggestion given in the answer to use a loop in an optimization problem. The use of a optimization expression C in the code below is intended to be similar in terms of relevant elements to add and multiply as in the example given above but it contains the optimization variables. I get the error messages shown below when I run the code. I have also tried to write operations on C manually as shown in the last line of the code but I get the same error messages at the last line of the code Solution = solve(ALM).
How can I correct the code?
ERROR MESSAGES
Index exceeds the number of array elements (0).
Error in optim.internal.problemdef.SubsasgnExpressionImpl/computeLinearCoefficients
Error in optim.internal.problemdef.ExpressionTree/extractLinearCoefficients
Error in optim.internal.problemdef.ExpressionForest/extractLinearCoefficients
Error in optim.problemdef.OptimizationExpression/extractLinearCoefficients
Error in optim.problemdef.OptimizationConstraint/extractLinearCoefficients
Error in optim.problemdef.OptimizationProblem/compileConstraints
Error in prob2structImpl
Error in optim.problemdef.OptimizationProblem/solve
prices = [99.74 91.22 98.71 103.75 97.15];
cashFlows = [4 5 2.5 5 4; 4 5 2.5 5 4; 4 5 2.5 5 4; 4 5 2.5 5 4; 4 5 102.5 5 4;4 5 0 105 104;4 105 0 0 0; 104 0 0 0 0];
obligations = [5 7 7 6 8 7 20 0]'*1000;
nt=size(cashFlows,1)
nb=size(cashFlows,2)
Rates = [0.01; 0.015; 0.017;0.019;0.02;0.025;0.027;0.029];
EndTimes = (1:nt)';
Disc = rate2disc(1,Rates,EndTimes);
%Number of bonds available
nBonds = [10;100;20;30;5]
ALM = optimproblem;
bonds = optimvar('bonds',nb,'Type','integer','LowerBound',0,'UpperBound',nBonds);
ALM.ObjectiveSense = 'minimize';
ALM.Objective = prices*bonds;
%Define the constraint
B=[1.01;1.020024752;1.02101183;1.02502363;1.024009823;1.050370059;1.039082218;1.043109481];
A=-(cashFlows*bonds-obligations);
C = optimexpr(nt,1);
C(1) = A(1);
for k = 2:numel(A)
C(k) = C(k-1) * B(k) + A(k);
end
ALM.Constraints.Const1 = (C.*Disc)/53.844 <=0.05;
%Solve the problem
Solution = solve(ALM)
%Here I show the intended operation on Optimization Expression C (in case
%for loop above does not operate as intended but I get the same error messages
C=[A(1);A(1)*B(1)+A(2);(A(1)*B(1)+A(2))*B(2)+A(3);(A(1)*B(1)+A(2))*B(2)+A(3))*B(3)+A(4);...
((A(1)*B(1)+A(2))*B(2)+A(3))*B(3)+A(4))*B(4)+A(5);
(((A(1)*B(1)+A(2))*B(2)+A(3))*B(3)+A(4))*B(4)+A(5))*B(5)+A(6);...
((((A(1)*B(1)+A(2))*B(2)+A(3))*B(3)+A(4))*B(4)+A(5))*B(5)+A(6))*B(6)+A(7);...
(((((A(1)*B(1)+A(2))*B(2)+A(3))*B(3)+A(4))*B(4)+A(5))*B(5)+A(6))*B(6)+A(7))*B(7)+A(8)];
14 Comments
David Hill
on 8 Oct 2019
I don't understand your output, it repeats (1*10+3)*12+5; (1*10+3)*12+5; twice in the middle. Is that correct?
Matt J
on 10 Oct 2019
There is an inconsistency. This expression,
C=[A(1);A(1)*B(2)+A(2);(A(1)*B(2)+A(2))*B(3)+A(3);((A(1)*B(2)+A(2))*B(3)+A(3))*B(4)+A(4);...
(((A(1)*B(2)+A(2))*B(3)+A(3))*B(4)+A(4))*B(5)+A(5);((((A(1)*B(2)+A(2))*B(3)+A(3))*B(4)+A(4))*B(5)+A(5))*B(6)+A(6);...
(((((A(1)*B(2)+A(2))*B(3)+A(3))*B(4)+A(4))*B(5)+A(5))*B(6)+A(6))*B(7)+A(7);...
((((((A(1)*B(2)+A(2))*B(3)+A(3))*B(4)+A(4))*B(5)+A(5))*B(6)+A(6))*B(7)+A(7))*B(8)+A(8)];
doesn't use B(1) anywhere, while this example,
C = [1;1*10+3;1*10+3; (1*10+3)*12+5; ((1*10+3)*12+5)*14+7 ]
uses B(1) but doesn't use B(end).
The version here will be more efficient, but for such a small problem as this, the difference in efficiency will be irrelevant. Also, note that the problem-based optimization framework is slower than the solver-based. You are already working in a framework that does not prioritize speed. But again that's fine, because a problem this small won't benefit from speed optimization.
L Smith
on 10 Oct 2019
My actual problem is of much larger scale than the code I shared as I thought it will be easier for anyone to help out if I share a simple script that has all the data with a specific problem.
The problem structure you have shared will quickly encounter numerical difficulties as you try to generalize it to larger numbers of variables. Even for the slight increase in dimension shown in the following example data, you can see that the matrix elements blow up very quickly and will ultimately overflow.
A=[1;3;5;7;9;11] ; B = [10;12;14;19;21;23]
d=cumprod(B(1:end-1));
d=[1;d(:)];
M=tril(d./d.')
M =
1 0 0 0 0 0
10 1 0 0 0 0
120 12 1 0 0 0
1680 168 14 1 0 0
31920 3192 266 19 1 0
670320 67032 5586 399 21 1
L Smith
on 10 Oct 2019
Matt J
on 10 Oct 2019
I can't see how the problem generalizes when A and B are of different sizes.
L Smith
on 10 Oct 2019
I think if this results in a 100x100 matrix for M, it should not overflow.
Are B(i) always integers greater than 1? If so, then M(100,1)=prod(B) will always be at least
>> 2^100
ans =
1.2677e+30
Accepted Answer
More Answers (1)
I don't see a simple vectorized solution, but one for loop will be quite efficient:
A = [1;3;5;7]
B = [10;12;14;19]
C = nan(size(A)); % preallocate
C(1) = A(1);
for k = 2:numel(A)
C(k) = C(k-1) * B(k-1) + A(k);
end
Giving:
C =
1
13
161
2261
5 Comments
L Smith
on 8 Oct 2019
"The reason I want to avoid a loop is simply becuase ... loops can be quite slow."
This is a classic MATLAB myth.
Loops in themselves are not slow, and for many versions of MATLAB the JIT engine has optimized their internal operations. A well designed loop is fast, a badly designed loop is slow: this has nothing to do with the loop per se, but the code design. For that matter it is also possible to write very inefficient vectorized code (just because it is vectorized does not mean that somehow it is magically efficient).
Note that vectorized code can be very slow, especially when it requires large intermediate arrays to be stored in memory (and which would proably be required for this task).
Also keep in mind that the vectorized code will probably not be simple (as your own attempts have no doubt shown you), thus your code's efficiency will be:
runtime % unknown, possibly slower
writing time % slower
debugging time % slower
maintenance time % slower
Daniel M
on 9 Oct 2019
I have a hunch there is a very clever solution using something like conv2 or filter, but it would be much more complicated to understand than the loop.
L Smith
on 9 Oct 2019
Categories
Find more on Loops and Conditional Statements in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!