FMINCON to schedule appliance usage to minimize total cost - matlab

I would like to write a code to find the minimum cost of running a dishwasher. This is dependent on the power required, hourly tariff rate, and time used. I am using fmincon for this however the code provided below shows the following error message:
User supplied objective function must return a scalar value
My objective function is to minimize (Total Cost * Time) s.t total cost is equal to the summation of (hourly power)*(hourly cost) from hour 1 to 24 is equal to 0.8 kwh, also, the total cost must be greater than Ca and the total run time for the day is one hour.
% Array showing the hourly electricity rates (cents per kwh)
R=zeros(24,1);
R(1:7,1)=6;
R(20:24,1)=6;
R(8:11,1)=9;
R(18:19,1)=9;
R(12:17,1)=13;
p_7 = transpose([0.8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]); %This is the power pattern of appliance (operates at 0.8 kWh for 1 hour daily)
for k=1:23
P7(:, k+1) = circshift(p_7,k); % This shows all the possible hours of operation
end
Total = P7*R; % This is the total cost per hour at different hourly tariffs
fun = #(x)Total.*(x);
x0 = [1];
A = Total;
%Ca = 0.5;
Ca = ones(1,24);
b = Ca;
Aeq = Total;
Daily_tot_7 = 2*ones(1,24);
beq = Daily_tot_7;
ub = 24;
lb = 1;
x = fmincon(fun,x0,A,b,Aeq,beq,lb,ub)
I believe that my understanding on converting constraints to fmincon is not correct and that I may be missing vital constraints for this issue.

Your output is currently a vector of outputs. You stated that your cost function is the summation of hourly elements. Therefore, your function definition should be
fun = #(x)sum(Total.*(x));
However, if I'm reading into this right, you wish to solve for each hour individually. In that case, you need to set your x0 variable to be defined as a 24x1 input
x0 = ones(24,1);
If that is the case you need to adjust your A,b,Aeq, and beq variables accordingly. However, do you actually need these, you can just not use them by replacing them with []
Finally, your p7 variable is likely better redefined as
p7 = R*.8;
My apologies if I misunderstood what you are trying to accomplish here.

Related

Why does the rowsize of A matter in fmincon

I have a Matlab code, which use fmincon with some constraints. So that I am able to modify the code I have thought about whether the line position within the condition matrix A makes a difference
I set up a test file so I can change some variables. It turns out that the position of the condition is irrelevant for the result, but the number of rows in A and b plays a role. I´m suprised by that because I would expect that a row with only zeros in A and b just cancel out.
fun = #(x)100*(x(2)-x(1)^2)^2 + (1-x(1))^2;
options1 = optimoptions('fmincon','Display','off');
A=zeros(2,2); %setup A
A(2,2)=1; %x2<0
b=[0 0]'; %setup b
x = fmincon(fun,[-1,2],A,b,[],[],[],[],[],options1);x
%change condition position inside A
A=zeros(2,2);
A(1,2)=1; %x2<0
b=[0 0]';
x = fmincon(fun,[-1,2],A,b,[],[],[],[],[],options1);x
% no change; the position doesn´t influence fmincon
%change row size of A
A=zeros(1,2);
A(1,2)=1; %x2<0
b=[0]';
x = fmincon(fun,[-1,2],A,b,[],[],[],[],[],options1);x
%change in x2
%increase size of A
A=zeros(10,2);
A(1,2)=1; %x2<0
b=[0 0 0 0 0 0 0 0 0 0]';
x = fmincon(fun,[-1,2],A,b,[],[],[],[],[],options1);x
%change in x2
Can someone explain to me why fmincon is influenced by the row number? What is the "right" rownumber in A and b? The number of variables or the number of conditions?
EDIT
For reasons of completeness:
I agree that different values are possible because of the iteration process. Nevertheless I can find situations where the difference is bigger than the tolerance:
Added +log(x(2) to the function:
fun = #(x)100*(x(2)-x(1)^2)^2 + (1-x(1))^2+log(x(3));
options1 = optimoptions('fmincon','Display','off');
options = optimoptions('fmincon')
A=zeros(2,3); %setup A
A(2,3)=1; %x2<0
b=[0 0]'; %setup b
x = fmincon(fun,[-1,2,1],A,b,[],[],[],[],[],options1);x
%change row size of A
A=zeros(1,3);
A(1,3)=1; %x2<0
b=[0]';
x = fmincon(fun,[-1,2,1],A,b,[],[],[],[],[],options1);x
%change in x2
%increase size of A
A=zeros(10,3);
A(1,3)=1; %x2<0
b=[0 0 0 0 0 0 0 0 0 0]';
x = fmincon(fun,[-1,2,1],A,b,[],[],[],[],[],options1);x
%change in x2
x =
-0.79876 **0.49156** 2.3103e-11
x =
-0.79921 0.49143 1.1341e-11
x =
-0.80253 **0.50099** 5.8733e-12
Matlab support told me that the A matrix should not have more rows than conditions. Each condition makes it more difficult for the algorithm.
Note that fmincom doesn't necessarily give the exact solution but a good approximation of the solution according to a certain criteria.
The difference in results are plausible since fminconis an iterative algorithm and these matrix multiplications (even if there are mainly zeros) will eventually end with different results. Matlab will actually do these matrix multiplications until he finds the best result. So these results are all correct in the sense they are all close to the solution.
x =
0.161261791015350 -0.000000117317860
x =
0.161261791015350 -0.000000117317860
x =
0.161261838607809 -0.000000077614999
x =
0.161261877075196 -0.000000096088746
The difference in your results is around 1.0e-07 which is decent result considering you don't specify stopping criteria. You can see what you have by default with the command
options = optimoptions('fmincon')
My result is
Default properties:
Algorithm: 'interior-point'
CheckGradients: 0
ConstraintTolerance: 1.0000e-06
Display: 'final'
FiniteDifferenceStepSize: 'sqrt(eps)'
FiniteDifferenceType: 'forward'
HessianApproximation: 'bfgs'
HessianFcn: []
HessianMultiplyFcn: []
HonorBounds: 1
MaxFunctionEvaluations: 3000
MaxIterations: 1000
ObjectiveLimit: -1.0000e+20
OptimalityTolerance: 1.0000e-06
OutputFcn: []
PlotFcn: []
ScaleProblem: 0
SpecifyConstraintGradient: 0
SpecifyObjectiveGradient: 0
StepTolerance: 1.0000e-10
SubproblemAlgorithm: 'factorization'
TypicalX: 'ones(numberOfVariables,1)'
UseParallel: 0
For example, I can reach closer results with the option:
options1 = optimoptions('fmincon','Display','off', 'OptimalityTolerance', 1.0e-09);
Result is
x =
0.161262015455003 -0.000000000243997
x =
0.161262015455003 -0.000000000243997
x =
0.161262015706777 -0.000000000007691
x =
0.161262015313928 -0.000000000234186
You can also try and play with other criteria MaxFunctionEvaluations, MaxFunctionEvaluations etc to see if you can have even closer results...

MATLAB genetic algorithm constraint (all variables can't be zero at the same time in a binary environment)

I'm using MATLAB ga function for my optimization problem. In my problem, I have some decision variables which are integer (0 and 1: I specified lower bound, upper bound, and IntCon for it) plus two continues varibales. Otherwise, all integer variables can't be zero at same time, so at least, we need a single "one" variable among integers. How can I implement mentioned constraint in MATLAB?
This is a Mixed-Integer optimization problem and it can be solved using ga in MATLAB. As mentioned in the documentations: ga can solve problems when certain variables are integer-valued. Not all the variables but certain variables. So you should have at least one real variable among the other integers.
Whit IntCon options, you can specify which variables are integer, for instance IntCon=[1 3] means that your first and third variables are integer. To avoid both integer variables to be 0 at the same time, I think you can add some inequality constraints.
For instance look at the following example:
Let's say we want to find the optimum value for the Ackley function with 5 variables (e.g. in 5 dimensions), [x(1)...x(5)] and let's assume that the first and third variables, x(1) and x(3), are integers. We can write the following script:
nVar = 5;
lb = -5*ones(1,nVar); % define the upper bound
ub = 5*ones(1,nVar); % define the lower bound
rng(1,'twister') % for reproducibility
opts = optimoptions('ga','MaxStallGenerations',50,'FunctionTolerance',1e-3,'MaxGenerations',300);
[x,~,~] = ga(#ackleyfcn,nVar,[],[],[],[],lb,ub,[],[1 3],opts);
disp('solution:');disp(x)
On my machine, I get this solution:
solution:
0 -0.000000278963321 0 0.979067345808285 -0.000000280775000
It can be seen that x(1) and x(3) are integers and both 0. Now let's say as you mentioned, they both cannot be 0 at the same time and if one is 0 the other should be 1. Here the boundaries of the Ackley's problem allows the variables to be in the range defined by lower and upper bounds. However, in your case the lower and upper bounds should be defined as [0] and [1] for both integer variables.
Now I want to avoid both variables to be 0, so I can write the following linear inequality constraint:
% x(1) + x(3) >= 1
% x(1) >= 0
% x(3) > 0
These inequalities should be written in form Ax <= b:
A = [-1 0 -1 0 0
-1 0 0 0 0
0 0 -1 0 0];
b = [-1
0
0];
Now if we run the optimization problem again we see the effect of the constraints on the output:
[x,~,~] = ga(#ackleyfcn,nVar,A,b,[],[],lb,ub,[],[1 3],opts);
disp('solution');disp(x)
solution
1.000000000000000 -0.000005031565831 0 -0.000011740569861 0.000008060759466

cumsum with upper & lower limits?

I'd like to find a vectorized way to calculate the cumulative sums of a vector, but with upper and lower limits.
In my case, the input only contains 1's and -1's. You can use this assumption in your answer. Of course, a more general solution is also welcome.
For example:
x = [1 1 1 1 -1 -1 -1 -1 -1 -1];
upper = 3;
lower = 0;
s = cumsum(x) %// Ordinary cumsum.
s =
1 2 3 4 3 2 1 0 -1 -2
y = cumsumlim(x, upper, lower) %// Cumsum with limits.
y =
1 2 3 3 2 1 0 0 0 0
^ ^
| |
upper limit lower limit
When the cumulative sum reaches the upper limit (at the 3rd element), it won't increase anymore. Likewise, when the cumulative sum reaches the lower limit (at the 7th element), it won't decrease anymore. A for-loop version would be like this:
function y = cumsumlim(x, upper, lower)
y = zeros(size(x));
y(1) = x(1);
for i = 2 : numel(x)
y(i) = y(i-1) + x(i);
y(i) = min(y(i), upper);
y(i) = max(y(i), lower);
end
end
Do you have any ideas?
This is a somewhat hackish solution, but perhaps worth mentioning.
You can do the sum using a signed integer data type, and exploit the inherent limits of that data type. For this to work, the input needs to be converted to that integer type and multiplied by the appropiate factor, and an initial offset needs to be applied. The factor and offset are chosen as a function of lower and upper. After cumsum, the multiplication and offset are undone to obtain the desired result.
In your example, data type int8 suffices; and the required factor and offset are 85 and -128 respectively:
x = [1 1 1 1 -1 -1 -1 -1 -1 -1];
result = cumsum([-128 int8(x)*85]); %// integer sum, with factor and initial offset
result = (double(result(2:end))+128)/85; %// undo factor and offset
which gives
result =
1 2 3 3 2 1 0 0 0 0
I won't provide you with a magic vectorized way to do this, but I'll provide you with some data that probably will help you get on with your work.
Your cumsumlim function is very fast!
tic
for ii = 1:100
y = cumsumlim(x,3,0);
end
t = toc;
disp(['Length of vector: ' num2str(numel(x))])
disp(['Total time for one execution: ' num2str(t*10), ' ms.'])
Length of vector: 65000
Total time for one execution: 1.7965 ms.
I really doubt this is your bottleneck. Have you tried profiling the code?

Find index of min element in matlab

Here I have two matrix, one indicating cost and the other determines when to take into comparison.
cost = [0.2 0.0 0.3; 0.4 0 0; 0.5 0 0];
available = [1 1 0 ; 1 0 0; 0 0 0];
available = logical(available);
I want to get the index of the min available element in the cost matrix, which in this case would compare 0.2, 0.0 and 0.4 and return the index of 0.0, which is (1, 2) or 4 in the cost matrix.
I tried
mul = cost .* available; % Zero if not available, but I can't know if it is zero because cost is zero
mul(~mul) = nan; % Set zero to be NaN
[minVal, minId] = min(mul)
This will help to get the min non-zero cost but if there exists zero elements which are available, it would be wrong.
So is there a better way to do so?
Here are two possible solutions. Both essentially involve converting all non-available costs to Inf.
%#Set up an example
Cost = [0.2 0 0.3; 0.4 0 0; 0.5 0 0];
Available = [1 1 0; 1 0 0; 0 0 0];
%#Transform non-available costs to Inf
Cost(Available == 0) = Inf;
%#Obtain indices using find
[r, c] = find(Cost == min(min(Cost)))
%#Obtain linear indices and convert using ind2sub
[~, I1] = min(Cost(:));
[r2, c2] = ind2sub(size(Cost), I1);
Both solutions will only return the first minimum value in the instance that there is not a unique minimum. Also, the method will fail in the perverse case that all the available costs are Inf (but I guess you've got bigger problems if all your costs are infinite...).
I've done a few speed tests, and the second method is definitely faster, no matter what the dimensions of Cost, so should be strictly preferred. Also, if you only want linear indices and not subscript indices then you can of course drop the call to ind2sub. However, this doesn't give you huge savings in efficiency, so if there is a preference for subscript indices then you should use them.

change a value by a probability value in matlab

I want to change a variable by probability value,
as a example I have [ 0 0 1 1 1 1 0 1 ] in matlab and with probability = 0.01 change any elemet of it , how can I achive this in matlab?
(I want use this in GA and with p =0.01 do mutation of Gen of choromosome )
appreciate any help
First, identify all the elements you want to change
array = [0 0 1 1 1 1 0 1];
sizArray = size(array);
probability = 0.01;
toChangeIdx = rand(sizArray) < probability;
Then, you can flip zeros and ones where needed
array(toChangeIdx) = 1-array(toChangeIdx);
The relevant condition for your code is
if rand() < probability
% Flip your bit here, e.g.
% bitToFlip = randi(length(genome));
% genome(bitToFlip) = 1 - genome(bitToFlip);
end
This will run the code inside the if statement with a probability of exactly probability.