for loop in matlab - matlab

Hi I have the following code which I believe have indexed wrongly and so Im not getting the answer I am looking for
Diesel_matrix = xlsread('test_diesel.xlsx','Sheet2');
Diesel_supply = Diesel_matrix(:,1); % Power output of diesel generator
hourly_cost = Diesel_matrix(:,2); % Diesel cost of running genreator at that output
for z = 1:21
A = [-PV_supply -WT_supply -Diesel_supply(z)*ones(24,1)];
f = [CRF_PV*CC_PV; CRF_WT*CC_WT; (CRF_Diesel_generator*CC_Diesel)+sum(hourly_cost(1:z))] ;
b = -Demand;
[x,fval,exitflag] = linprog(f,A,b,[],[],lb,ub)
end
I am trying to loop only for the third column of matrix A.
I would like to loop for all the rows in "Diesel_supply" per row of matrix A
at the moment, the code works for 21 sets of x outputs but column 3 is either row 1,2,3 etc up to row 21 of "Diesel_supply". Wheras I am trying to get it for row 1 and 2 and 3 and 4 etc up to row 21 of "Diesel_supply".
This will allow me to examine all the elements in "Diesel_Supply"

Per the conversation #user643469 and I had in chat (see link in comments section) and looking at the documentation for linprog afterwards, I think you need to store the results of each z-iteration in a data structure and then pick the best one after the loop has finished.
As I understand, the generator has 21 different modes you can run it in and it is subject to 24 different constraints. Each mode changes the constaints a little.
Instead of
[x,fval,exitflag] = linprog(f,A,b,[],[],lb,ub)
use
val = linprog(f,A,b,[],[],lb,ub)
results(z) = val;
After the loop has finished, you will be left with a results matrix with the dimensions 4x21 where the first column contains x-values, second contains fval values and third contains exitflag values. You can then you through this 'results' matrix to determine which of the 21 modes you have available to run the generator in.

Related

Perform an operation on indexed/grouped elements of an array in Matlab [duplicate]

I'm working in Matlab.
I have a two-dimensional matrix with two columns. Lets consider elements in the first column as labels. Labels may be repeated.
How to multiply all elements in the second column for every label?
Example:
matrix = [1,3,3,1,5; 2,3,7,8,3]'
I need to get:
a = [1,3,5; 16,21,3]'
Can you help me with doing it without for-while cycles?
I would use accumarray. The preprocessing with unique assigns integer indices 1:n to the values in the first row, which allow accumarray to work without creating unnecessary bins for 2 and 4. It also enables the support for negative numbers and floats.
[ulable,~,uindex]=unique(matrix(:,1))
r=accumarray(uindex,matrix(:,2),[],#prod)
r=[ulable,r]
/You can also use splitapply:
[ulable,~,uindex]=unique(matrix(:,1))
r=splitapply(#prod,matrix(:,2),uindex)
r=[ulable,r]
You can do it without loops using accumarray and the prod function:
clear
clc
matrix = [1,3,3,1,5; 2,3,7,8,3]';
A = unique(matrix,'rows');
group = A(:,1);
data = A(:,2);
indices = [group ones(size(group))];
prods = accumarray(indices, data,[],#prod); %// As mentionned by #Daniel. My previous answer had a function handle but there is no need for that here since prod is already defined in Matlab.
a = nonzeros(prods)
Out = [unique(group) a]
Out =
1 16
3 21
5 3
Check Lauren blog's post here, accumarray is quite interesting and powerful!
Try something like this, I'm sure it can be improved...
unValues = unique(matrix(:,1));
bb = ones(size(unValues));
for ii = 1:length(unValues)
bb(ii) = bb(ii)*prod(matrix(matrix(:, 1) == unValues(ii), 2));
end
a = [unValues bb];

Using Matlab to randomly split an Excel Sheet

I have an Excel sheet containing 1838 records and I need to RANDOMLY split these records into 3 Excel Sheets. I am trying to use Matlab but I am quite new to it and I have just managed the following code:
[xlsn, xlst, raw] = xlsread('data.xls');
numrows = 1838;
randindex = ceil(3*rand(numrows, 1));
raw1 = raw(:,randindex==1);
raw2 = raw(:,randindex==2);
raw3 = raw(:,randindex==3);
Your general procedure will be to read the spreadsheet into some matlab variables, operate on those matrices such that you end up with three thirds and then write each third back out.
So you've got the read covered with xlsread, that results in the two matrices xlsnum and xlstxt. I would suggest using the syntax
[~, ~, raw] = xlsread('data.xls');
In the xlsread help file (you can access this by typing doc xlsread into the command window) it says that the three output arguments hold the numeric cells, the text cells and the whole lot. This is because a matlab matrix can only hold one type of value and a spreadsheet will usually be expected to have text or numbers. The raw value will hold all of the values but in a 'cell array' instead, a different kind of matlab data type.
So then you will have a cell array valled raw. From here you want to do three things:
work out how many rows you have (I assume each record is a row) by using the size function and specifying the appropriate dimension (again check the help file to see how to do this)
create an index of random numbers between 1 and 3 inclusive, which you can use as a mask
randindex = ceil(3*rand(numrows, 1));
apply the mask to your cell array to extract the records matching each index
raw1 = raw(:,randindex==1); % do the same for the other two index values
write each cell back to a file
xlswrite('output1.xls', raw1);
You will probably have to fettle the arguments to get it to work the way you want but be sure to check the doc functionname page to get the syntax just right. Your main concern will be to get the indexing correct - matlab indexes row-first whereas spreadsheets tend to be column-first (e.g. cell A2 is column A and row 2, but matlab matrix element M(1,2) is the first row and the second column of matrix M, i.e. cell B1).
UPDATE: to split the file evenly is surprisingly more trouble: because we're using random numbers for the index it's not guaranteed to split evenly. So instead we can generate a vector of random floats and then pick out the lowest 33% of them to make index 1, the highest 33 to make index 3 and let the rest be 2.
randvec = rand(numrows, 1); % float between 0 and 1
pct33 = prctile(randvec,100/3); % value of 33rd percentile
pct67 = prctile(randvec,200/3); % value of 67th percentile
randindex = ones(numrows,1);
randindex(randvec>pct33) = 2;
randindex(randvec>pct67) = 3;
It probably still won't be absolutely even - 1838 isn't a multiple of 3. You can see how many members each group has this way
numel(find(randindex==1))

Matlab matching first column of a row as index and then averaging all columns in that row

I need help with taking the following data which is organized in a large matrix and averaging all of the values that have a matching ID (index) and outputting another matrix with just the ID and the averaged value that trail it.
File with data format:
(This is the StarData variable)
ID>>>>Values
002141865 3.867144e-03 742.000000 0.001121 16.155089 6.297494 0.001677
002141865 5.429278e-03 1940.000000 0.000477 16.583748 11.945627 0.001622
002141865 4.360715e-03 1897.000000 0.000667 16.863406 13.438383 0.001460
002141865 3.972467e-03 2127.000000 0.000459 16.103060 21.966853 0.001196
002141865 8.542932e-03 2094.000000 0.000421 17.452007 18.067214 0.002490
Do not be mislead by the examples I posted, that first number is repeated for about 15 lines then the ID changes and that goes for an entire set of different ID's, then they are repeated as a whole group again, think first block of code = [1 2 3; 1 5 9; 2 5 7; 2 4 6] then the code repeats with different values for the columns except for the index. The main difference is the values trailing the ID which I need to average out in matlab and output a clean matrix with only one of each ID fully averaged for all occurrences of that ID.
Thanks for any help given.
A modification of this answer does the job, as follows:
[value_sort ind_sort] = sort(StarData(:,1));
[~, ii, jj] = unique(value_sort);
n = diff([0; ii]);
averages = NaN(length(n),size(StarData,2)); % preallocate
averages(:,1) = StarData(ii,1);
for col = 2:size(StarData,2)
averages(:,col) = accumarray(jj,StarData(ind_sort,col))./n;
end
The result is in variable averages. Its first column contains the values used as indices, and each subsequent column contains the average for that column according to the index value.
Compatibility issues for Matlab 2013a onwards:
The function unique has changed in Matlab 2013a. For that version onwards, add 'legacy' flag to unique, i.e. replace second line by
[~, ii, jj] = unique(value_sort,'legacy')

MATLAB vector: prevent consecutive values from same range

Okay, this might seem like a weird question, but bear with me.
So I have a random vector in a .m file, with certain constraints built into it. Here is my code:
randvecall = randsample(done, done, true);
randvec = randvecall([1;diff(randvecall(:))]~=0);
"Done" is just the range of values we take the sample from, so don't worry about that. As you can see, this randsamples from a range of values, and then prunes this random vector with the diff function, so that consecutive duplicate values are removed. There is still the potential for duplicate values in the vector, but they simply cannot be consecutive.
This is all well and good, and works perfectly fine.
So, say, randvec looks like this:
randvec =
54
47
52
26
39
2
14
51
24
6
19
56
34
46
12
7
41
18
29
7
It is actually a lot longer, with something like 60-70 values, but you get the point.
What I want to do is add a little extra constraint on to this vector. When I sample from this vector, the values are classified according to their range. So values from 1-15 are category 1, 16-30 are category 2, and so on. The reasons for this are unimportant, but it is a pretty important part of the program. So if you look at the values I provided above, you see a section like this:
7
41
18
29
7
This is actually bad for my program. Because the value ranges are treated separately, 41, 18, and 29 are used differently than 7 is. So, for all intents and purposes, 7 is appearing consecutively in my script. What I want to do is somehow parse/modify/whatever the vector when it is generated so that the same number from a certain range cannot appear twice "in a row," regardless of how many other numbers from different ranges are between them. Does this make sense/did I describe this well? So, I want MATLAB to search the vector, and for all values within certain ranges (1-15,16-30,31-45,46-60) make sure that "consecutive" values from the same range are not identical.
So, then, that is what I want to do. This may not by any means be the best way to do this, so any advice/alternatives are, of course, appreciated. I know I can do this better with multiple vectors, but for various reasons I need this to be a single, long vector (the way my script is designed it just wouldn't work if I had a separate vector for each range of values).
What you may want to do is create four random vectors, one for each category, ensure that they do not contain any two consecutive equal values, and then build your final random vector by ordered picking of values from random categories, i.e.
%# make a 50-by-nCategories array of random numbers
categories = [1,16,31,46;15,30,45,60]; %# category min/max
nCategories = size(categories,2);
randomCategories = zeros(50,nCategories);
for c=1:nCategories
%# draw 100 numbers for good measure
tmp = randi(categories(:,c),[100 1]);
tmp(diff(tmp==0)) = []; %# remove consecutive duplicates
%# store
randomCategories(:,c) = tmp(1:50);
end
%# select from which bins to pick. Use half the numbers, so that we don't force the
%# numbers of entries per category to be exactly equal
bins = randi(nCategories,[100,1]);
%# combine the output, i.e. replace e.g. the numbers
%# '3' in 'bins' with the consecutive entries
%# from the third category
out = zeros(100,1);
for c = 1:nCategories
cIdx = find(bins==c);
out(cIdx) = randomCategories(1:length(cIdx),c);
end
First we assign each element the bin number of the range it lies into:
[~,bins] = histc(randvec, [1 16 31 46 61]);
Next we loop for each range, and find elements in those categories. For example for the first range of 1-16, we get:
>> ind = find(bins==1); %# bin#1 of 1-16
>> x = randvec(ind)
ans =
2
14
6
12
7
7
now you can apply the same process of removing consecutive duplicates:
>> idx = ([1;diff(x)] == 0)
idx =
0
0
0
0
0
1
>> problematicIndices = ind(idx) %# indices into the vector: randvec
Do this for all ranges, and collect those problematic indices. Next decide how you want to deal with them (remove them, generate other numbers in their place, etc...)
If I understand your problem correct, I think that is one solution. It uses unique, but applies it to each of the subranges of the vector. The values that are duplicated within a range of indices are identified so you can deal with them.
cat_inds = [1,16,31,46,60]; % need to include last element
for i=2:numel(cat_inds)
randvec_part = randvec( cat_inds(i-1):cat_inds(i) );
% Find the indices for the first unique elements in this part of the array
[~,uniqInds] = unique(randvec_part,'first');
% this binary vector identifies the indices that are duplicated in
% this part of randvec
%
% NB: they are indices into randvec_part
%
inds_of_duplicates = ~ismember(1:numel(randvec_part), uniqInds);
% code to deal with the problem indices goes here. Modify randvec_part accordingly...
% Write it back to the original vector (assumes that the length is the same)
randvec( cat_inds(i-1):cat_inds(i) ) = randvec_part;
end
Here's a different approach than what everyone else has been tossing up. The premise that I'm working on here is that you want to have a random arrangement of values in a vector without repitition. I'm not sure what other constraints you are applying prior to the point where we are giving out input.
My thoughts is to use the randperm function.
Here's some sample code how it would work:
%randvec is your vector of random values
randvec2 = unique(randvec); % This will return the sorted list of values from randvec.
randomizedvector = randvec2(randperm(length(randvec2));
% Note: if randvec is multidimensional you'll have to use numel instead of length
At this point randomizedvector should contain all the unique values from the initial randvec and but 'shuffled' or re-randomized after the unique function call. Now you could just seed the randvec differently to avoid needing the unique function call as simply calling randperm(n) will returning a randomized vector with values ranging from 1 to n.
Just an off the wall 2 cents there =P enjoy!

Matrix operations in MatLab

I have a 10 X 10 matrix, A, created in MatLab. All the values in the matrix are between 0 and 100. Say that I want to:
Replace all elements of A < 10 with zeros
Replace all elemtns of A > 90 with infinity
Extract all values between 30 and 50 to a new vector.
Can I do this without writing a script? I can easliy do this through a script with some simple for-loops, but are there any shortcuts available? Any help will be greatly appreciated!
All of these things are really easy to do using logical indexing:
Each of the operations above can be done quite easily using a one or two commands. However each operation must be done independent of the other two. You can't do all 3 in one line.
1.
smallIdx = A<10;
A(smallIdx) = 0;
% One Line Version
A(A<10) = 0;
2.
bigIdx = A>90;
A(bigIdx)=inf;
% One Line Version
A(A>90) = inf;
3.
middleIdx = A>30 & A<50;
newVector = A(middleIdx);
% One Line Version
newVector = A(A>30 & A<50);
new vector is a vector and wont be square like A was
Set up any 3 × 3 matrix a. Write some command-line statements to perform the following
operations on a:
(a) interchange columns 2 and 3;
(b) add a fourth column (of 0s);
(c) insert a row of 1s as the new second row of a (i.e., move the current second and third rows
down);
(d) remove the second column.