How can I determine the amount of times a certain value can be achieved by summing values in a matrix?

1 view (last 30 days)
I have a vector of up to 50 whole numbers, all of which are length values for wall panels. The wall panels come in sections of 144 inches, so my goal is to apply the lengths from the matrix and determine the number of full wall panels I would need. For example:
LengthVal = [50 50 60 70]; %User Input
With the values above, I know I would ned two 144 in panels: the 70 and 60 on one with the 50 and 50 on the other. I want to do this programetrically with a much larger number of length values. I assume the solution will require several for loops, but I am unsure about how to implement that. Are there any short cuts that you may know to perform a similar function?
Edit: Essentially, I want to get something with similar functionality to this website.
Thanks for any help!
  4 Comments
Walter Roberson
Walter Roberson on 31 Jul 2020
Is the requirement the minimum number of pieces used and any solution that achieves that is acceptable? Is the requirement the minimum total waste? Is the requirement that assuming that you are using the minimum number of pieces, that you want to maximize the waste width -- because the larger the waste pieces the more likely that you could use one of them for a later job?

Sign in to comment.

Answers (3)

Matt J
Matt J on 31 Jul 2020
Edited: Matt J on 31 Jul 2020
This solution (EDITED) requires the Optimization Toolbox:
LengthVal = [50,50 ,60,70]; %User Input
N=numel(LengthVal);
X=optimvar('X',[N,N],'LowerBound',0,'UpperBound',1,'type','integer');
y=optimvar('y',[1,N],'LowerBound',0,'UpperBound',1,'type','integer');
prob=optimproblem('Objective',sum(y));
prob.Constraints.row=sum(X,2)==1; %assign exactly 1 panel to each wall
prob.Constraints.capacity=LengthVal*X<=144; %respect panel capacity
prob.Constraints.ylb=sum(X,1)/N<=1.1*y;
prob.Constraints.yub=sum(X,1)>=y;
sol=solve(prob);
[~,~,groups]=unique((1:N)*round(sol.X.'),'stable') %the result, as a grouping vector
groups =
1
2
1
2
  15 Comments
Matt J
Matt J on 31 Jul 2020
Edited: Bruno Luong on 31 Jul 2020
Very well, but I wonder if it is good to have as an explicit constraint anyway to help the algorithm narrow the search...
Bruno Luong
Bruno Luong on 31 Jul 2020
In my experience no.
By removing the redundancy of the constraints, we'll help the minimizer for not doing extra calculation for when it needs to update the active set.

Sign in to comment.


Bruno Luong
Bruno Luong on 31 Jul 2020
Edited: Bruno Luong on 31 Jul 2020
I put here the code with limiting CPU time so one can run up to 50 samples. Matt should get credit for his original idea.
fulllength = 144;
% Random LengthVal
LengthVal = randi(fulllength,1,50)
N=numel(LengthVal);
X=optimvar('X',[N,N],'LowerBound',0,'UpperBound',1,'type','integer');
y=optimvar('y',[1,N],'LowerBound',0,'UpperBound',1,'type','integer');
prob=optimproblem('Objective',sum(y));
prob.Constraints.row=sum(X,2)==1; %assign exactly 1 panel to each wall
prob.Constraints.capacity=LengthVal*X<=fulllength; %respect panel capacity
for j=1:N
for i=1:N
prob.Constraints.(sprintf('Bnd_i%dj%d',i,j))=X(i,j)<=y(1,j);
end
end
problem = prob2struct(prob);
problem.options = optimoptions('intlinprog','MaxTime',60); % limits the computation to 60s
x = intlinprog(problem);
% Post process data
X = reshape(x(1:N^2),[N,N]);
X = round(X);
X(:,all(X==0,1)) = [];
ng = size(X,2);
FillLengths=LengthVal*X;
L = X.*LengthVal(:);
N = cumsum(X,1).*X;
[~,g,n] = find(N);
data = accumarray([g,n],L(X>0),[],[],NaN);
% Graphic output
figure(1);
clf
subplot(1,2,1);
imagesc(X);
xlabel(sprintf('group (1-%d)', ng));
ylabel('Wall paper number');
subplot(1,2,2);
bar(1:ng,data,'stacked');
xlim([0.5 ng+0.5]);
ylim([0 fulllength]);
xlabel(sprintf('group (1-%d)', ng));
ylabel('stack lengths');
Examples of results:

Matt J
Matt J on 2 Aug 2020
Below is a more advanced version of my original answer, which is showing greater empirical succes. It incorporates initialization and restart strategies to iterative reduce problem dimension, and hence the run time. On 3 consecutive sets of randomized inputs with N=50,
LengthVal = (randi(10,1,50)*10);
it was able to complete the optimization within a few minutes. However, for some cases, it does still fall into a protracted branch and bound phase, so I have chosen an empirical cap for the MaxNodes option parameter:
N=numel(LengthVal);
e=ones(N,1);
sol=init(LengthVal);
M=sum(sol.y);
tic;
while 1
X=optimvar('X',[N,M],'LowerBound',0,'UpperBound',1,'type','integer');
y=optimvar('y',[1,M],'LowerBound',0,'UpperBound',1,'type','integer');
prob=optimproblem('Objective',sum(y));
prob.Constraints.rowLB=sum(X,2)>=0.5; %assign exactly 1 panel to each wall
prob.Constraints.rowUB=sum(X,2)<=1.5;
prob.Constraints.capacity=LengthVal*X<=144; %respect panel capacity
% prob.Constraints.ylb=sum(X,1)/N<=1.1*y;
prob.Constraints.ylb=X/2<=e*y;
%prob.Constraints.yub=sum(X,1)+0.5>=y;
prob.Constraints.mono=sum(X(:,1:M-1),1)>=sum(X(:,2:M),1);
of=@(x,o,s) customFcn(x,o,s,M);
cut=logical(sol.y);
sol.X=sol.X(:,cut);
[~,is]=sort(sum(sol.X,1),'descend');
sol.X=sol.X(:,is);
sol.y=sol.y(cut);
[sol,fval]=solve(prob,sol,...
'options',optimoptions(@intlinprog,'OutputFcn',of,...
'MaxNodes',M*20000));
fval=round(fval),
if fval==M, break; end
M=fval;
end
toc;
[~,~,groups]=unique((1:M)*round(sol.X.'),'stable'); %the result, as a grouping vector
grous=groups(:).',
function stop = customFcn(x,optimValues,state,M)
stop=false;
if ~isempty(optimValues.fval) && ~isempty(x)
stop=optimValues.fval<M;
end
end
function sol=init(LengthVal)
N=numel(LengthVal);
sol.X=zeros(N);
j=1; accum=0;
for i=1:N
accum=accum+LengthVal(i);
if accum<=144
sol.X(i,j)=1;
else
accum=LengthVal(i); j=j+1;
sol.X(i,j)=1;
end
end
sol.y=double(any(sol.X,1));
end

Tags

Community Treasure Hunt

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

Start Hunting!