How can I create a vector with constrains on Matlab?
3 次查看(过去 30 天)
显示 更早的评论
I have been working on this for two days and I'm becoming crazy.
I need to create several different vectors where 1 is repeated 46 times, 2 is repeated 40 times and 3 is repeated 45 times. 1 2 and 3 have to alternate with constrains:
- no repetition of 2 identical numbers one after the other
- between two equal numbers (1 or 2) there has to be a 3
How can I do it? Thank you very much
回答(5 个)
KSSV
2020-7-23
编辑:KSSV
2020-7-23
A = ones(1,46) ;
B = 2*ones(1,40) ;
C = 3*ones(1,45) ;
iwant = [A B C] ; N = length(iwant) ;
% randomise the vector
idx = randperm(N) ;
iwant = iwant(idx) ;
% check if any number repeating
Now from the vector iwant, find the pattern [1 1], [2 2], [3 3] ..get those positions. to get this use:
Once you got the indices, you can insert the number 2 or 3 for repeating [1 1], etc using:
Hayden Garmon
2020-7-23
Does this work for you?
% b=combnk(1:46,40); if you want to make many vectors, run a for loop with rows from this
b=1:40; % example trial
a=[];
for i=1:46
a=[a,1];
if find(find(b(1,:)==i))==1
a=[a,2];
end
a=[a,3];
end
FINAL=a(1:end-1)
0 个评论
Clemens Gersch
2020-7-23
I can give you a starting point:
nOnes = 1;
nTwos = 2;
nThrees = 2;
% Create permutations.
Elements = [repmat(1, 1, nOnes), repmat(2, 1, nTwos), repmat(3, 1, nThrees)];
PermsPossible = perms(Elements);
PermsPossible = unique(PermsPossible,'rows');
Of course you have to change the first three lines. What you get are all the possible combinations of a sequence of numbers that satisfies that the amount of each number is as you speciefied it in the first three lines of code
What is left to do is filtering out the invalid solutions according to your constraints.
Therefore you can use strfind to check for tuples and triples, but you probably need to proceed row by row.
1 个评论
Clemens Gersch
2020-7-24
Another approach could be to start with the set of sequence of length 1 ([1;2;3]), then for each of the three sequences of length 1 form all allowed sequences of length 2 and so on.
That would mean: One loop over the length of the sequences (2:46+40+45), one nested loop over the number of sequences you have at the beginning of each loop. In the inner loop you check for each of the three numbers if it can be added to form a valid sequence.
As conditions you have then not only the 2 conditions you stated but also the three conditions on the numbers used, e.g. a running out of ones condition where you check if the number of ones within a sequence is already 46, so that you don't place a 47th one by accident.
To illustrate:
Starting point is [1;2;3]
First iteration yields [ 1,2 ; 1,3 ; 2,1 ; 2,3 ; 3,1 ; 3,2 ] (here 'no repetition of 2 identical numbers one after the other' is triggered, that why three possible sequences are missing)
That should be very easy to implement. The only point where it might get a bit difficult is the 'between two equal numbers (1 or 2) there has to be a 3' condition. Just think of it as
If the last but one number is the number you check to be set, it can only be set if the previous number is a three.
John D'Errico
2020-7-24
One approach would be to construct the set of all possible sequences of length perhaps 10.
seq10 = char(dec2base(0:59048,3) + 1);
k = any(diff(seq10,[],2) == 0,2);
seq10(k,:) = [];
This produces a set of 1536 sequences of length 10.
size(seq10)
ans =
1536 10
seq10(1:100:end,:)
ans =
16×10 char array
'1212121212'
'1213212312'
'1232123121'
'1312313212'
'1321231212'
'1323231312'
'2123132121'
'2131323212'
'2312312121'
'2321212312'
'2323213121'
'3123123212'
'3131321212'
'3212131312'
'3213232121'
'3232132312'
some of which are shown above. Of course, this is still too broad of a set, as it includes sequences that are illegal. I next need to exclude sequences that do not contain a 3 in a subsequence [1 ? 1] or [2 ? 2]. Therefore, I just need to exclude any strings in this set that contain either '121' or '212' as a substring.
n10 = size(seq10,1);
k = false(n10,1);
for i = 1:n10
k(i) = ~isempty(strfind(seq10(i,:),'121')) | ~isempty(strfind(seq10(i,:),'212'));
end
seq10(k,:) = [];
n10 = size(seq10,1)
n10 =
552
Too early in the morning for me to think of how to use regexp to do that last operation. Sorry. There are 552 such sequences of length 10. The problem is, this scheme becomes intractable when sequences of length say 15 or 20 must be constructed. Constructing all possible sequences of a longer length would be difficult.
Therefore, consider a different approach, where I'll construct the set of all admissable sequences recursively.
Suppose a given sequence ends with the subsequence: '12'. The next element canot be 1, since then we have the subsequence '121'. It cannot be 2, since then we swould have '122'. This means the next element must ALWAYS be 3.
Similarly, suppose the sequence ends with '13'. Now the legal continuations are always either '132' or '131'.
finallength = 30;
seqs2 = ['12';'13';'21';'23';'31';'32'];
% allseqs = seqs2;
for n = (size(allseqs,2)+1):finallength
newseqs = '';
for i = 1:6
k = ismember(allseqs(:,[end-1,end]),seqs2(i,:),'rows');
nk = sum(k);
switch i
case {1 3}
% allseqs ends in '12' or '21'. the next element must always be '3'
newseqs = [newseqs;[allseqs(k,:),repmat('3',nk,1)]];
case {2 4}
% allseqs ends in '13' or '23'. the next element must be either '1' or '2'
newseqs = [newseqs;[allseqs(k,:),repmat('1',nk,1)];[allseqs(k,:),repmat('2',nk,1)]];
case 5
% allseqs ends in '31'. the next element must be either '2' or '3'
newseqs = [newseqs;[allseqs(k,:),repmat('2',nk,1)];[allseqs(k,:),repmat('3',nk,1)]];
case 6
% allseqs ends in '32'. the next element must be either '1' or '3'
newseqs = [newseqs;[allseqs(k,:),repmat('1',nk,1)];[allseqs(k,:),repmat('3',nk,1)]];
end
end
allseqs = newseqs;
end
size(allseqs)
The code above, with finallength as successively [5,10,15,20,25,30], yields the number of all possible sequences as respectively [32, 552, 9568, 165888, 2876160, 49866752]. I cannot go much beyond that point.
Of those roughly 50 million possible sequences of length 30. We could choose one at random.
seq = allseqs(randi(n30),:)
seq =
'232323132321323132131232131231'
accumarray(seq' - '0',1)
ans =
8
10
12
So in this initial sequence of length 30, we found 8 ones, 10 twos, and 12 threes. We could now append one of the sequences from allseqs, as long as it starts in a way that is compatible with the terminating characters of seq, and as long as the total number of 1,2,3 elements are not more than the target of 46,40,45.
0 个评论
另请参阅
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!