Linear Programming with summations in MatLab - matlab

I am trying to replicate a linear optimisation that I found in a research paper in Matlab. I need to solve the following linear optimisation problem:
where C1, C2, C3, C4, C5, w1 and w2 are priority weightings.
j is taken from 1 to 12 (12 months of the year).
The following constraints apply:
I(j) and L(j) are monthly recordings.
I used MatLab to program a solution. Here is my code (I am quite new to this, so please forgive any bad coding!):
%set up the data for the year:
I = [72.6 26.0 23.2 20.4 15.2 22.0 40.9 45.2 38.7 41.4 142.2 116.8]
L = [1.6 1.3 0.8 0.6 0.6 0.6 1 1.5 1.8 1.8 1.8 2.0];
%set up the initial level:
S0 = 683
%set up the priority weightings
w2= 1;
w1 = 1.5;
C1 = 3;
C2 = 2;
C3 = 5;
C4 = 4;
C5 = -5;
%set up the constraint equation, lower bond and upper bound
A = [(C1*w1) C2 (C3*w2) (C4*w2) C5];
Aeq = [1 1 1 1 1];
lb = [70 0 0 0 0];
ub = [815 54.14 13.4 41.8 17345];
%set up a blank matrix to store the results
x=zeros(12,5);
%for each month calculate the optimum and store in the matrix
for j = 1:12
Beq = [(I(j)+S0-L(j))];
x(j,:) = linprog(-A,[],[],Aeq,Beq,lb,ub);
S0 = x(j,1);
end
%output the result
opt = x
The problem is when I compare my results to the research paper I find that I am getting different results. Eventually I realised that I am finding the optimum for each month, rather than a global optimum for the year. I have been searching online for how to find an optimum for the whole year (i.e. to optimize the summation function) but I can't find anything. Can anyone point me in the right direction?

Thanks to #ErwinKalvelagen I was able to solve my problem. Here is my solution for others in future:
%set up the data for the year:
I = [72.6; 26.0; 23.2; 20.4; 15.2; 22.0; 40.9; 45.2; 38.7; 41.4; 142.2; 116.8;];
I = I*1; %allows the inflow to be scaled to test the model for a dry or wet year
L = [1.6; 1.3; 0.8; 0.6; 0.6; 0.6; 1; 1.5; 1.8; 1.8; 1.8; 2.0;];
%set up the priority weightings
w1 = 2;
w2= 50;
C1 = 3;
C2 = 2;
C3 = 5;
C4 = 4;
C5 = -5;
%set up the constraint equation, lower bond and upper bound
A = [(C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5 (C1*w1) C2 (C3*w2) (C4*w2) C5];
%set up spare matrix for Aeq
Aeq = zeros(12,60);
% Populate Aeq
% first the positive portions of the monthly data
row = 1;
coloumn = 1;
for counter = 1:12
for counter = 1:5
Aeq(coloumn,row)=1;
row = row + 1;
end
coloumn = coloumn+1;
end
% then the -S0 for each month
Aeq(1, 56)=-1;
coloumn = 1;
for row = 2:12
Aeq(row,coloumn)=-1;
coloumn = coloumn+5;
end
%populate Beq
Beq = I-L;
%populate the lower and upper bounds
Smin = 70;
Smax_1_9 = 731.2;
Smax_10_12 = 673.2
QDmin = 0
QDmax = 54.14
Rmin = 0;
Rmax = 13.4;
RRmin = 0;
RRmax = 41.8;
SPILLmin = 0;
SPILLmax = 17345;
%first the lower bound
lbmonthly = [Smin; QDmin; Rmin; RRmin; SPILLmin;];
lb = vertcat(lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly,lbmonthly);
%second the upper bound
ubmonthly_1_9 = [Smax_1_9; QDmax; Rmax; RRmax; SPILLmax;];
ubmonthly_10_12 = [Smax_10_12; QDmax; Rmax; RRmax; SPILLmax;];
ub = vertcat(ubmonthly_1_9, ubmonthly_1_9, ubmonthly_1_9, ubmonthly_1_9, ubmonthly_1_9, ubmonthly_1_9, ubmonthly_1_9, ubmonthly_1_9, ubmonthly_1_9, ubmonthly_10_12, ubmonthly_10_12, ubmonthly_10_12);
%find the optimal
opt = linprog(-A,[],[],Aeq,Beq,lb,ub);
%output the result as a matrix
opt = reshape(opt,5,12)'

Related

matlab system of equations with one unchanging solution ('q')

I am trying to solve a model of 4 equations, where everything is real. It is essentially a pipe branch problem with "1" being upstream of the pump (with some head on it), and "2" and "3" are downstream w/o head. The units are English.
Anyway, I'm just solving the system of 4 equations and 4 unknowns and looking at a plot of head (ha) vs. total flow rate (Q1). Across this space though I only am collecting points in a vertical line, i.e. the head changes but the flowrate doesn't.
I was thinking the problem may be some variables are being held onto, but I treat "ha" the same as "Q1" so that doesn't seem likely... Realistically, this is matching a system curve to a pump curve, and of course that point moves when the system changes (both flowrate and head), so it seems I am doing something wrong....
Here is the script:
clear sol1 sol2 sol3 sol4 S q h
clc; clearvars; close all;
syms Q1 Q2 Q3 ha
D1 = 1.25/12; Z1 = 0; P1 = 62.4*10; A1 = pi*(1/4)*D1*D1; f1 = 0.011; L1 = 50;
D2 = 0.5/12; Z2 = 25; P2 = 0; A2 = pi*(1/4)*D2*D2; f2 = 0.011; L2 = 100; %V2 = Q2 / A2;
D3 = 0.5/12; Z3 = 10; P3 = 0; A3 = pi*(1/4)*D3*D3; f3 = 0.011; L3 = 100; %V3 = Q3 / A3;
gamma = 62.468;
origPumpData = [0 150; 0.4 148; 0.8 145; 1.2 143; 1.6 141; 2 139; 2.4 138; 2.8 136; 3.2 134; 3.6 132; 4 130; 4.4 128; 4.8 127; 5.2 125; 5.6 124; 6 121; 6.4 118; 6.8 117; 7.2 115; 7.6 113; 8 111; 8.4 110; 8.8 108; 9.2 106; 9.6 104; 10 102; 10.4 100; 10.8 98; 11.2 97;
11.6 94; 12.0 93; 12.4 91; 12.8 89; 13.2 87; 13.6 86; 14 84; 14.4 82; 14.8 80; 15.2 78; 15.6 76; 16 74; 16.4 72; 16.6 70];
pumpData(:,1) = origPumpData(:,1)/448.8312;
pumpData(:,2) = origPumpData(:,2);
polyFit = fit(pumpData(:,1),pumpData(:,2),'poly2');
assume(in(Q1,'real') & Q1 > 0.0001 & Q1 < 1 );
assume(in(Q2,'real') & Q2 > 0.0001 & Q2 < 1 );
assume(in(Q3,'real') & Q3 > 0.0001 & Q3 < 1 ) ;
assume(in(ha,'real') & ha > 0.0001 & ha < 1000.0);
eq1 = #(Q1) polyFit.p1*Q1*Q1 + polyFit.p2*Q1 + polyFit.p3;
eq2 = #(P1,Z1,F1,Q1,A1,L1,D1,P2,Z2,F2,Q2,A2,L2,D2) P1/gamma + ((Q1/A1)^2)/64.4 + Z1 - hf(F1,L1,D1,Q1,A1) - hf(F2,L2,D2,Q2,A2) + ha == P2/gamma + ((Q2/A2)^2)/64.4 + Z2;
eq3 = #(P1,Z1,F1,Q1,A1,L1,D1,P3,Z3,F3,Q3,A3,L3,D3) P1/gamma + ((Q1/A1)^2)/64.4 + Z1 - hf(F1,L1,D1,Q1,A1) - hf(F3,L3,D3,Q3,A3) + ha == P3/gamma + ((Q3/A3)^2)/64.4 + Z3;
eq4 = Q1 == Q2 + Q3;
guesses = [0.07116936917086152675558661517184;
0.035125850031368916048762418970837;
0.036043519139492610706824196201003;
303.02361035523126099594683749354];
for i = 1:1:2
disp(i)
disp(Z1)
Z1 = Z1-5
f1 = f1+0.01
f3 = f3 + 0.01
S(i) = vpasolve([eq1(Q1) eq2(P1,Z1,f1,Q1,A1,L1,D1,P2,Z2,f2,Q2,A2,L2,D2) eq3(P1,Z1,f1,Q1,A1,L1,D1,P3,Z3,f3,Q3,A3,L3,D3) eq4], [Q1 Q2 Q3 ha], guesses )
S(i).Q1
S(i).Q2
S(i).Q3
S(i).ha
q(i) = S(i).Q1
h(i) = S(i).ha
guesses = [S(i).Q1 S(i).Q2 S(i).Q3 S(i).ha]'
clear S
end
plot( q, h, '*b');
function hf = hf(f,L,D,Q,A)
hf = f*(L/D)*(1/64.4)*(Q/A)^2;
end
you're solving eq1 == 0(default) and computing Q1, independent of other equations and parameters. that's why you get constant Q1 in every iteration.

Fit a Fourier Model with zero a0

following code finds coefficients in Fourier series
load enso;
f = fit(month,pressure,'fourier2');
output of the code:
General model Fourier1:
f(x) = a0 + a1*cos(x*w) + b1*sin(x*w)
Coefficients (with 95% confidence bounds):
a0 = 10.63 (10.22, 11.03)
a1 = 2.876 (2.187, 3.565)
b1 = 1.177 (0.09191, 2.261)
w = 0.5263 (0.5225, 0.5301)
I need to find coefficients for function f(x) = a1*cos(x*w) + b1*sin(x*w), so a0 should be either 0 or should not be in the formula at all. How to do this?
Do you want 'fourier1' or 'fourier2'? Because you have both in your question. You can limit a0 to 0 by using fit options. Below are the fits for both, the -Inf to Inf are ranges for the a's, b's and w while the 0 to 0 is limiting a0.
load enso;
ft1 = fittype('fourier1');
options1 = fitoptions(ft1);
options1.Lower = [0 -Inf -Inf -Inf];
options1.Upper = [0 Inf Inf Inf];
f1 = fit(month,pressure,ft1,options1)
ft2 = fittype('fourier2');
options2 = fitoptions(ft2);
options2.Lower = [0 -Inf -Inf -Inf -Inf -Inf];
options2.Upper = [0 Inf Inf Inf Inf Inf];
f2 = fit(month,pressure,ft2,options2)
Edit:
It runs fine for me. That's odd...
f1 =
General model Fourier1:
f1(x) = a0 + a1*cos(x*w) + b1*sin(x*w)
Coefficients (with 95% confidence bounds):
a0 = 0 (fixed at bound)
a1 = 2.258 (-1.631, 6.148)
b1 = 2.406 (-1.317, 6.13)
w = 0.5311 (0.516, 0.5462)

Combinations from a given set without repetition

Suppose I have a matrix defined as follows
M = [C1 C2 C3 C4]
Where the C's are column vectors
I want some efficient (i.e. no for loops) way of producing A vector such that
ResultVec = [C1 C2;
C1 C3;
C1 C4;
C2 C3;
C2 C4;
C3 C4]
Thanks in advance!
That is, what nchoosek does:
M = [ 1 2 3 4 ];
R = nchoosek(M,2);
returns:
R =
1 2
1 3
1 4
2 3
2 4
3 4
I don't know if it's your intention but nchoosek is Matlabs implementation of The number of k-combinations from a given set S of n elements without repetition (Wikipedia)
The function nchoosek is performance wise not very efficient though. But there are equivalents on File Exchange, which are much(!!) faster and doing the same.
Just to make it clear, it's not just working for the fairly simple example above, and is not returning any indices. It directly transforms the matrix as desired.
M = [ 21 42 123 17 ];
returns:
R =
21 42
21 123
21 17
42 123
42 17
123 17
This is the simplest way I've come up with:
n = size(M, 2);
[j, i] = ind2sub([n n], find(~triu(ones(n))));
ResultVec = M(:, [i j]);
ResultVec = reshape(ResultVec, [], 2)

transform matrix and repeat values

I have this matrix:
a1 a2 a3 a4 a5
b1 b2 b3 b4 b5
c1 c2 c3 c4 c5
d1 d2 d3 d4 d5
e1 e2 e3 e4 e5
and i need to transform it to this matrix:
a1 a2 a3 b1 b2 b3 c1 c2 c3
a2 a3 a4 b2 b3 b4 c2 c3 c4
a3 a4 a5 b3 b4 b5 c3 c4 c5
b1 b2 b3 c1 c2 c3 d1 d2 d3
b2 b3 b4 c2 c3 c4 d2 d3 d4
b3 b4 b5 c3 c4 c5 d3 d4 d5
c1 c2 c3 d1 d2 d3 e1 e2 e3
c2 c3 c4 d2 d3 d4 e2 e3 e4
c3 c4 c5 d3 d4 d5 e3 e4 e5
i.e. by taking a 3x3 matrix and iterating over the old matrix putting it as a new row in the new matrix.
How can i do this in matlab? I heard loops are very bad and if I can I should use matrix operations.
If you have access to image processing toolbox you can use im2col which even works for symbolic variables too.
A = sym('A%d%d', [5 5]);
A = sym(A, 'real');
Subs = mat2cell(im2col(A, [3 1])', 3*ones(1,5));
Res = im2col(Subs, [3 1]);
Res is a cell matrix containing the sub matrices.
To concatenate it into a matrix:
reshape([Res{:}]', [9 9])
or if it's not symbolic this also works: cell2mat(Res).
Take a look at this code :
clear
clc
a1 = 1; a2 = 2; a3 = 3; a4 = 4; a5 = 5;
b1 = 11; b2 = 12; b3 = 13; b4 = 14; b5 = 15;
c1 = 21; c2 = 22; c3 = 23; c4 = 24; c5 = 25;
d1 = 31; d2 = 32; d3 = 33; d4 = 34; d5 = 35;
e1 = 41; e2 = 42; e3 = 43; e4 = 44; e5 = 45;
A = [a1 a2 a3 a4 a5; b1 b2 b3 b4 b5; c1 c2 c3 c4 c5; d1 d2 d3 d4 d5; e1 e2 e3 e4 e5];
B = zeros(9,9);
sizeA = size(A);
sizeB = size(B);
jj = 1;
kk = 1;
for ii = 1 : sizeB(1)
B(ii,1:sizeB(1)) = [A(kk, jj:jj+2) A(kk + 1, jj:jj+2) A(kk + 2, jj:jj+2)]
jj = jj + 1;
if mod(ii,3) == 0
kk = kk + 1;
jj = 1;
end
end
I tested it for your case where A is 5x5 and B is 9x9. Might need to be modified to work with different size of A and B.
You can do this in a somewhat general sense, but it is not pretty:
a = [a1, a2, a3, a4, a5];
b = [b1, b2, b3, b4, b5];
% etc.
% Rearrange your vector into a matrix configured how you want it
A = flipdim(toeplitz(a),1); % 5 x 5 matrix in our case
A = A(ceil(size(A,1)/2):size(A,1), ceil(size(A,2)/2):size(A,2)); % now 3 x 3
%%%
% Repeat similar process for b --> B, c --> C, etc.
%%%
% Build the resulting matrix up block-by-block
M = [A, B, C;
B, C, D;
C, D, E];
I was unable to find a good way to generalize the construction of M, and unfortunately forming a toeplitz matrix using toeplitz([a,b,c,d,e]) fails; you do not get the right format for your sub-matrices. Still, you may be able to use this to start on something.

Difference between skewness function and skewness formula result

Consider the matrix
c =
1 2
3 4
m = 2;
n = 2;
% mean
% sum1 = uint32(0);
b4 = sum(c);
b5 = sum(b4');
c5 = b5 / ( m * n )
% standard deviation
sum2 = uint32(0);
for i = 1 : m
for j = 1 : n
b = ( double(c(i,j)) - c5 ) ^ 2 ;
sum2 = sum2 + b ;
end
end
sum3 = sum2 / ( m * n );
std_dev = sqrt(double(sum3))
% skewness
sum9 = 0;
for i = 1 : m
for j = 1 : n
skewness_old = ( ( double(c(i,j)) - c5 ) / ( std_dev) )^ 3 ;
sum9 = sum9 + skewness_old ;
end
end
skewness_new = sum9 / ( m * n )
The skewness result is 0
If I use the matlab function skewness,
skewness(c)
c =
1 2
3 4
skewness(c)
ans =
0 0
Why is the function skewness returning two 0's, While the formula returns only one 0
MATLAB function SKEWNESS by default calculates skewness for each column separately. For the whole matrix do skewness(c(:)).