How to find a second number by having first number and distance between these 2 numbers - maple

I am so new to maple and I dont know what to do exactly! I have 10 numbers, for finding k nearest number to any of this number I need to keep distances between all numbers and sort them, based on these distances I can get which x is the nearest x to current number so:
for i from 1 to 10 do
for j from 1 to 10 do
dist[j] := abs(x[i]-x[j]);
result[i,j] := abs(x[i]-x[j]);
end do;
end do;
for h from 1 to 10 do
for k from 1 to 10 do
arr[k] := result[h,k];
end do;
distances := (quicksort(arr,1,10));
for t from 1 to 10 do
sortedMatrix[h,t] := distances[t];
end do;
end do;
print(sortedMatrix);
Now I have distances and a number, but i dont know what the other number is?

If I understand correctly, you start with an array of N elements and you want, for each of those N elements, the nearest neighbour in that array.
My approach would be to just sort the array first and then loop over it, setting each elements nearest neighbour equal to its neighbour in the sorted array.
Example: suppose you have the array [5,1,86,54,23,46]. If you sort that, you get [1,5,23,46,54,86]. To find the nearest neighbours, you go over the array and look at both elements adjacent. For example, 46 has 23 and 54 as neighbouring elements in the sorted array. 45 is closest to 54 so that's his neighbour.
There is no need to calculate all distances (n*n differences) between elements, you only need the distances between neighbouring nodess in the sorted array (2*n differences).
You can expand that for k nearest neighbours by looking to the k nearest neighbours in the sorted array (2*k*n differences).

Related

Produce 6 different number by only use "randi" and some loops

I want to only use "randi" this function to produce the 6 different number randomly in matlab ,and the range of these 6 number is 1 ~ 12.
number=randi([1,12],1,6)
c=0;
for n=1:6%when "n" is 1 to 6
while c <= 6 %while c is less equal than 6,do the program below
c = c + 1; %c=c+1
if number(n) == number(c) %when the nth element is equal to cth element
number(n) = randi(12); %produce a random integer in the nth element
c = 0; %the reason why i set c=0 again is because i want to check again whether the new random integer is the same as cth element or not
end
end
end
final_number=number
but the result still show me like
1 "2" 6 11 "2" 3
5 "8" "8" 12 3 1
How do i improve my code to produce 6 different numbers.i don't want to always rely on the convenient matlab instruction too much,so my tags will also write c.hoping someone can help me to improve this
If you're trying to reproduce randsample (or randperm), why not just reproduce the algorithm MATLAB uses? (As far as we can tell...)
This is the Fisher-Yates shuffle. If you have a vector v, each iteration selects a random, previously unused element and puts it at the end of the unselected elements. If you do k iterations, the last k elements of the list are your random sample. If k equals the number of elements in v, you've shuffled the entire array.
function sample = fisher_yates_sample(v, k)
% Select k random elements without replacement from vector v
% if k == numel(v), this is simply a fisher-yates shuffle
for n = 0:k-1
randnum = randi(numel(v)-n); % choose from unused values
% swap elements v(end-n) and v(randnum)
v([end-n, randnum]) = v([randnum, end-n]);
end
sample = v(end-k+1:end);
end
Unlike MATLAB's version, mine requires a vector as input, so to get 6 random values in the range 1:12 you'd call the function like this:
>> fisher_yates_sample(1:12,6)
ans =
5 11 6 10 8 4
Since you're re-selecting single random numbers, when there is one occuring multiple times, why not just re-selecting all numbers at once?
% Initial selecting of random numbers.
number = randi([1, 12], 1, 6)
% While the amount of unique elements in numbers is less than 6:
while (numel(unique(number)) < 6)
% Re-select random numbers.
number = randi([1, 12], 1, 6)
end
And since you wrote, you specifically want to use the randi method, I guess there is a reason, you don't want to use randperm(12, 6)!?
What you are looking for is randperm. It produces a random permutation of a range of integers, so that if you select the first k numbers, you are sure that you get k unique integers in the range [1;n].
In your case, simply call:
randperm(12,6)

Matlab: Array of random integers with no direct repetition

For my experiment I have 20 categories which contain 9 pictures each. I want to show these pictures in a pseudo-random sequence where the only constraint to randomness is that one image may not be followed directly by one of the same category.
So I need something similar to
r = randi([1 20],1,180);
just with an added constraint of two numbers not directly following each other. E.g.
14 8 15 15 7 16 6 4 1 8 is not legitimate, whereas
14 8 15 7 15 16 6 4 1 8 would be.
An alternative way I was thinking of was naming the categories A,B,C,...T, have them repeat 9 times and then shuffle the bunch. But there you run into the same problem I think?
I am an absolute Matlab beginner, so any guidance will be welcome.
The following uses modulo operations to make sure each value is different from the previous one:
m = 20; %// number of categories
n = 180; %// desired number of samples
x = [randi(m)-1 randi(m-1, [1 n-1])];
x = mod(cumsum(x), m) + 1;
How the code works
In the third line, the first entry of x is a random value between 0 and m-1. Each subsequent entry represents the change that, modulo m, will give the next value (this is done in the fourth line).
The key is to choose that change between 1 and m-1 (not between 0 and m-1), to assure consecutive values will be different. In other words, given a value, there are m-1 (not m) choices for the next value.
After the modulo operation, 1 is added to to transform the range of resulting values from 0,...,m-1 to 1,...,m.
Test
Take all (n-1) pairs of consecutive entries in the generated x vector and count occurrences of all (m^2) possible combinations of values:
count = accumarray([x(1:end-1); x(2:end)].', 1, [m m]);
imagesc(count)
axis square
colorbar
The following image has been obtained for m=20; n=1e6;. It is seen that all combinations are (more or less) equally likely, except for pairs with repeated values, which never occur.
You could look for the repetitions in an iterative manner and put new set of integers from the same group [1 20] only into those places where repetitions have occurred. We continue to do so until there are no repetitions left -
interval = [1 20]; %// interval from where the random integers are to be chosen
r = randi(interval,1,180); %// create the first batch of numbers
idx = diff(r)==0; %// logical array, where 1s denote repetitions for first batch
while nnz(idx)~=0
idx = diff(r)==0; %// logical array, where 1s denote repetitions for
%// subsequent batches
rN = randi(interval,1,nnz(idx)); %// new set of random integers to be placed
%// at the positions where repetitions have occured
r(find(idx)+1) = rN; %// place ramdom integers at their respective positions
end

MATLAB busy, loop works well until i=29996, when i=29997 stay Busy

I am writing code which compares the data of a vector. It should count how many positions (acc) have equal values, and save a specific value in a vector of the same length of the quantity of positions (n_T(acc)).
My data vector is [30000 x 1]. For example, first 80 positions have the same value, next 60 positions have the same value, etc., next 5 positions have the same value.
The code works well if I use just 29996 values. I do not understand why when I try to use the complete vector MATLAB stays Busy.
Checking my data vector, I noticed that the last 5 positions are equivalent [29996:30000]. Could it be the reason, and what should I change?
Following is the code
%========================================================
%ac: data vector`
%acc1: accumulator which count how much positions have the same value
%n_T: vector which presents the values I need, in the same positions the data is equal
%m: show a value where i should begin
%========================================================
i=m; %previously used`
fv=length(ac)
while i<fv %29996
acc1=0;
for i=m+1:fv
if ac(i)==ac(i-1)
acc1=acc1+1; % count how much positions are equals
else
m=i;
break
end
end
mi=m-acc1; %define where the data n_T should begin
for i=mi:m
n_T(i)=tm/acc1; %create a vector with length [acc x1] begining in mi and finishing in m
end
m=i;
end
plot(n_T)
Does it work if you do this in a vectorized way? Not completely sure what you want the program to output.
% locate repeated elements
eq_els = ac(diff(ac) == 0);
% count number of repeated elements (unique)
unique_els = unique(eq_els);
num_equal_els = numel(unique_els);
% create variable-length lists for each unique element
each_eq_list = cell(num_equal_els,1);
for (k = 1:num_equal_els)
% each vector in the cell array is equal to the elements of ac that are equal to the current unique item
each_eq_list{[k]} = ac(ac == unique_els(k));
end
The length of each_eq_list{[k]} is the length of the total number of contiguous repeated values of repeated value k.

filling a matrix with random integers from a range according to a rule

I'm using the matrix as an initial population for multiobjective optimization using NSGA-II in matlab. The size of my chromosome vector,(C), is 1x192 and each gene must be within the range 0<=gene<=40 and the genes must be integers. The rule is that the sum of groupings of 6 genes must be less or equal to 40.that is:
sum(reshape(6,[]))<=40
I've use the following code but it outputs either an all-zero population matrix(population matrix=vertical concatenation of 500 chromosomes) or a matrix that does not satisfy the rule:
X=zeros(500,192);
while i<501
r=randi(40,6,32);
if nnz(((sum(r))./40)>1)==0
X(i,:)=reshape(r,1,[]);
i=i+1;
clear r;
else
clear r;
end
end
It is also taking forever to exit the while loop.
What am I doing wrong here? Is there another way of doing the above?
I've also tried this:
i=1;
while i<17500
r=randi([1,40],6,1);
s=sum(r);
if s<=40
X(:,i)=r;
i=i+1;
else
clear r;
end
end
X=unique(X','rows')';
A=X(:,randperm(size(X,2)));
A=X(randperm(size(X,1)),:);
The above tries to create random columns that will be reshaped to the population matrix. But the numbers are repeating; i.e in the 17500(16448 after removing duplicate columns) columns there is no occurrence of the numbers 37 and 40. Is there any way I can optimize the spread of the generated random numbers?
#0x90
I have a vector,called 'chromosome', of size 1x192 and each successive group of 6 members(called phenotype) must sum to 40 or less. To make it clearer:
That is, each P must be an integer in the range 0 to 40 inclusive and the sum at each phenotype must be <=40. I need 500 chromosomes like this.
I hope it makes sense now. ><
You should use randi([min,max],n,m). randint is going to be deprecated.
>> r = randi([1,4],3,2)
r =
3 3
2 2
4 4

find lowest neighbor matlab

I am trying to write a function
[offset,coffset]=findLowNhbr(map)
that for each pixel in a map finds the eight neighbors to the pixel, and returns two matrices with both the row and column offsets to the lowest neighbor (uses the numbers -1, 0 and 1). Border pixels are given 0 offsets for both the row and column, since they do not have neighbors.
Here is what I think the general plan for this function should be:
For each point, find the eight nearest neighbors.
If the neighbor is lower than the point, return -1
If the neighbor is at the same elevation as the point, return 0
If the neighbor is higher than the point, return +1
Store these offsets in two matrices.
I am at a complete loss as to where to start, so any advice or questions are welcome!
Not entirely sure what you mean, but here's something to get you well on your way:
neighbors = cell(size(map));
for ii = 2:size(map,1)-1
for jj = 2:size(map,1)-1
% current element
M = map(ii,jj);
% extract neighbors
N = map(ii-1:ii+i, jj-1:jj+1);
% compare values and store
neighbors{ii,jj} = M<N - M>N;
end
end
This will result in a cell-array neighbors, which contains the same number of elements as map, but each entry looks something like this:
>> neighbors{2,3}
ans =
0 -1 1
1 0 -1
1 0 -1
which is the information on all neighbors of pixel (2,3).
Edit: This is how you can add inf to all sides of the map, assuming that map_original is your original map.
map=inf(size(map_original)+2)
map(2:end-1,2:end-1) = map_original
Assuming you have padded the map with infs on all sides, here is something to get you started:
area =-1:1;
for i=2:size(map,1)-1
for j = 2:size(map,2)-1
bestfound=inf;
bestk=0;
bestl=0;
for k = area
for l=area
if k~=0 && l~=0
Like i said, this will only get you started !