how to output selectively a random matrix

1 view (last 30 days)
Brian Kim
Brian Kim on 18 Sep 2017
Commented: Brian Kim on 21 Sep 2017
i have code. I'll explain this and then ask you a question.
function numcase_ewn=Numcase_MW(ewn,col_l)
tmp_ewn=fix(ewn);
sum_te=sum(tmp_ewn);
sum_te=fix(sum_te);
final=[];
for i1=1:1:10
for i2=1:70000
A=sort(round(8*rand(col_l,1)+4));
sumA=sum(A);
if sumA==sum_te && A(1)==tmp_ewn(1)
final=[final A];
end
end
BBB=final(:,:);
sum(BBB);
BBB=unique(BBB','rows');
numcase_ewn=BBB';
end
--------- Input ---------
'ewn' is the matrix I know.
'col_l' is col's length.
------------------------
In conclusion, this function places the matrices for the same sum into separate rows.
For example,
if ewn=[4 4 4 4 5], col_l=3,
'numcase_ewn' is
numcase_ewn = [ 4 4 4 4
5 6 7 8
12 11 10 9]
by the way, I use this function to write the main code
I thought this function is so slow.
Therefore, i want to revise this.
((((P.S. If possible, let me know if there is a way to get a matrix that only gets one case, instead of getting a set of all cases matrices.)))

Answers (1)

Cam Salzberger
Cam Salzberger on 18 Sep 2017
Hello Brian,
From both your question and your code, I cannot understand what you are trying to get out of this. What is "numcase_ewn" in comparison to "ewn"? For that matter, what do you mean by "case" in regards to numbers? Are you just looking for an example matrix that has the same sum as "ewn" and starts with the same number, but is somewhat randomly generated otherwise? Because that could probably be done in 3 lines or so.
I can give you advice on specific issues I see with your code, even if I don't fully understand what you are trying to do with it.
sum_te=fix(sum_te);
No need for this, as all values within "tmp_ewn" were "fixed" already.
round(8*rand(col_l,1)+4)
is the same as:
randi([4 12], col_l, 1)
and using randi tends to be more readable.
sumA=sum(A);
If a value is not going to be used more than once, generally no need to make a separate variable to store it, at least if the calculation to complete it is simple.
final=[final A];
This could potentially be a large time-sink. You are growing the size of an array in a loop, which requires allocating new memory blocks nearly every time. Even if you don't know the size of the output array, I'd still recommend preallocation unless you can make a strong argument against it. Pay attention to the code analyzer warnings.
BBB=final(:,:);
is the same as:
BBB = final;
so why not just use "final"?
sum(BBB);
doesn't assign its output to anything, so you can get rid of it.
The biggest time-sink though is that you have two loops going on, but you are using the indices for nothing, and you may not need to be looping like that. As far as I can tell, the loop limits were chosen randomly to ensure that you "tried a lot to find an answer", but they don't guarantee that you have an answer, or that you have only one answer.
If by "get a matrix that only gets one case, instead of getting a set of all cases matrices", you mean that you want only one of these arrays that corresponds to "ewn", rather than constantly concatenating on new ones that fit the criteria, then a while loop is probably the way to go. Just loop while you haven't yet found a matrix that fits the criteria. That will "guarantee" exactly one answer, though it may still take a long time since this algorithm has Bogosort-level efficiency.
-Cam
  3 Comments
Cam Salzberger
Cam Salzberger on 19 Sep 2017
I don't know why you are checking if "A" contains values outside of 4 and 13. What do you want to happen in that case? Currently, your code will still proceed with "final" being assigned to an empty array, but only after it found a valid matrix. If you always want "final" to be empty if A has values exceeding the limits, then you should probably do this at the beginning:
if max(A(:)) > 13 || min(A(:)) < 4
final = [];
return
end
so that the loop is never entered.
This:
else
continue
is never needed as the last few lines in a loop. The loop will continue without this.
Yes, this code will likely work for what you are trying to do, if I understand what you are trying to do correctly. Again, however, it is entirely random as to when it will work. The runtime complexity is O(n!), which is about as bad as it gets.
If for example, you just need a semi-randomly-generated array that adds up to some value, I'd suggest something like:
  1. Preallocate output array to correct size
  2. Set limits on integer values that are acceptable within the array
  3. Enter loop through each index in array
  4. Calculate minimum value you would need for the "ith" entry in order to meet the total (if all subsequent entries are the max allowable value)
  5. If that minimum value is over the max allowed value, then the array is not possible
  6. Calculate maximum value if all subsequent entries are the minimum possible value
  7. If that value is under the minimum allowable value then the array is not possible
  8. Select random integer between the maximum of the two minimum values, and the minimum of the two maximum values, and place that in the "ith" position in the array
  9. Loop until array is built
This is just one possible way to do it though. Really depends on what you're going for and whether you have restrictions on how you generate the array.
Brian Kim
Brian Kim on 21 Sep 2017
thank you so much :) I was so inspired by your answers.

Sign in to comment.

Categories

Find more on Creating and Concatenating Matrices in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!