i use factor(n) in matlab but it don't work for numbers like ((10^11-1)/11),for same number what can i do? - matlab

I use factor(n) in matlab but it don't work for numbers like ((10^11-1)/11) - what can I do? My source is here.
m=input('Enter your number: ');
i=0;
while (i<m)
if(isprime(i))
% sum=factor((10^(i-1)-1));
sum=factor((10^(i-1)-1)/i);
disp(sum);
end
i =i+1;
end
but for large n it returns errors!!
>> FactorGen
Enter your number: 45
3 3
3 3 11
3 3 11 101
3 3 3 7 11 13 37
3 3 11 41 271 9091
3 3 3 7 11 13 37 101 9901
Error using factor (line 26) When n is single or double, its maximum
allowed value is FLINTMAX.
Error in FactorGen (line 7) sum=factor((10^(i-1)-1));
I want the function factor((10^(i-1)-1)) to work for same number. How can I solve my problem?

I think this can be partially alleviated by converting your large number into uint64 format. For R2014b maximum integer that can be handled is:
n = intmax('uint64')
n = 1.8447e+19
While the maximum double that can be handled is:
n = flintmax('double')
n = 9.0072e+15
This can be verified by simple example. Let's use factor on the number larger than flintmax. First, try double:
factor(10^16)
Error using factor (line 26)
When n is single or double, its maximum allowed value is FLINTMAX.
Now, we try uint64:
factor(uint64(10^16))
ans = 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
So, using factor(uint64(x)) increases your limit by several orders. Indeed, there's no sense in using double format for factor function.
By the way, since using factor on large numbers may freeze your system, I suggest using this function:
function f = Factorize(n)
i = 0;
while mod(n,2) == 0
i = i + 1;
n = n/2;
f(i) = 2;
disp([2,n])
end
q = round(sqrt(double(n)));
q = q + 1 - mod(q,2);
for j = 3:2:q
while mod(n,j) == 0
i = i + 1;
f(i) = j;
n = n/j;
end
end
if n > 2;
i = i + 1;
f(i) = n;
end
It is much faster for large numbers and does not overload the system at large n
Hope that helps

Related

How can I calculate the relative frequency of a row in a data set using Matlab?

I am new to Matlab and I have a basic question.
I have this data set:
1 2 3
4 5 7
5 2 7
1 2 3
6 5 3
I am trying to calculate the relative frequencies from the dataset above
specifically calculating the relative frequency of x=1, y=2 and z=3
my code is:
data = load('datasetReduced.txt')
X = data(:, 1)
Y = data(:, 2)
Z = data(:, 3)
f = 0;
for i=1:5
if X == 1 & Y == 2 & Z == 3
s = 1;
else
s = 0;
end
f = f + s;
end
f
r = f/5
it is giving me a 0 result.
How can the code be corrected??
thanks,
Shosho
Your issue is likely that you are comparing floating point numbers using the == operator which is likely to fail due to floating point errors.
A faster way to do this would be to use ismember with the 'rows' option which will result in a logical array that you can then sum to get the total number of rows that matched and divide by the total number of rows.
tf = ismember(data, [1 2 3], 'rows');
relFreq = sum(tf) / numel(tf);
I think you want to count frequency of each instance, So try this
data = [1 2 3
4 5 7
5 2 7
1 2 3
6 5 3];
[counts,centers] = hist(data , unique(data))
Where centers is your unique instances and counts is count of each of them. The result should be as follow:
counts =
2 0 0
0 3 0
0 0 3
1 0 0
1 2 0
1 0 0
0 0 2
centers =
1 2 3 4 5 6 7
That it means you have 7 unique instances, from 1 to 7 and there is two 1s in first column and there is not any 1s in second and third and etc.

Finding where a set of values lie within a matrix

I have two values (k and j) which I know are within an nx3 matrix (M). I know that they're and on the same row and that j is always to the right of k, so if k is in M(2,1), then j will be in M(2,2). I tested for this earlier in the function, but now I want to know which row that is for a given k and j. I need the row number of their location to proceed. There are no duplicate combinations of k and j in the matrix.
So if I have the matrix
M=
1 4 5
1 5 7
k j 5
4 5 6
2 3 1
Then I want to know that they're in row 3. None of the columns are ordered.
What I have tried:
I used the code below
[row,~] = find(M==k);
I'm not sure how to look for a combination of them. I want to avoid using the find function. I hope to potentially use logical indexing.
How do I go about doing this? I hope this question makes sense.
You can use bsxfun -
find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
Being a relational operation with bsxfun, according to this post on benchmarked results, this should be pretty efficient.
Sample runs
Case #1 :
A =
1 4 5
1 5 7
6 7 1
4 5 6
2 3 1
k =
6
j =
7
>> find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
ans =
3
Case #2 :
A =
1 4 5
1 5 7
1 6 7
4 5 6
2 3 1
k =
6
j =
7
>> find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
ans =
3
Slightly different version on bsxfun. This one doesn't limit the matrix to three columns.
find(sum(((bsxfun(#eq,M,j) + bsxfun(#eq,M,k)) .* M).' ) == j+k >0)
Case 1:
M = [
1 4 5
1 5 7
6 7 1
4 5 6
2 3 1]
k=6;j=7;
ans = 3
Case 2:
M=[
1 4 5
1 5 7
1 6 7
4 5 6
2 3 1
];
k=6;j=7;
ans = 3
Use this:
row = find(((M(:,1) == k ) & ( M(:,2) == j)) | ((M(:,1) == k ) & ( M(:,3) == j)) | ((M(:,2) == k ) & ( M(:,3) == j)) )
Also, logical indexing can only give you a matrix with zeros at all other positions and one at your required position. But to get the index of that position, you will have to use find.

Comparing values across matrices with a tolerance range

I have 4 matrices having X,Y,Z co-ordinates of different points.say the matrices are:
A=[ 1 2 5 5; 2 3 4 4; 44 5 65 55]
B=[ 1 3 4 5; 2 3 14 146; 4 5 45 1]
C=[ 2 4 5 6 ; 4 5 6 8; 3 44 5 66]
D=[4 5 6 8; 1 3 4 5; 12 3 4 5]
I want to check whether there are any common point across the four matrices. I have a tolerance of +/- 1 for each of X,Y,Z.
I can run a loop for this but there is the problem of complexity coming up:
when the number of matrices increases the the complexity of the code increases hugely. Any way out regarding this?
Any better procedure regarding the problem?
Your question is a bit unclear, but I am assuming you are looking for indices i,j for which A(i,j)==B(i,j)==C(i,j)==D(i,j), within some tolerance? If so this code will work.
A=[ 1 2 5 5; 2 3 4 4; 44 5 65 55];
B=[ 1 3 4 5; 2 3 14 146; 4 5 45 1];
C=[ 2 4 5 6 ; 4 5 6 8; 3 44 5 66];
D=[4 5 6 8; 1 3 4 5; 12 3 4 5];
% concatenate A,B,C,D into a Nrow x Ncol x Nvars matrix
M = cat(3, A,B,C,D);
% find maximum and minimum along dimension 3
maxVal = max(M, [], 3);
minVal = min(M, [], 3);
% find which row,col indices have a range within 0.00001
valRange = maxVal - minVal;
matchPoints = (valRange <= 0.00001);
% boolean value representing if any match was found
matchFound = any(matchPoints(:));
thank you for your reply.I wrote this function to compare two matrices:
function [comp] = compare( A, B )
[m,n]= size(A);
[mm,nn]=size(B);
k=1;
comp=[];
for ii=1: m
for i=1:mm
if A(ii,1) < (B(i,1)+2) & A(ii,1)> (B(i,1)-2)
if A(ii,2) < (B(i,2)+2) & A(ii,2)> (B(i,2)-2)
if A(ii,3) < (B(i,3)+2) & A(ii,3)> (B(i,3)-2)
comp(k,:)= [A(ii,:), B(i,:)];
k=k+1;
else continue
end
else continue
end
else continue
end
end
end
end
My data is an output of activated co-ordinates of brain across several days. So I want to group regions ( across days) that are nearby each other in a cluster. I tried to attach a picture to explain what I want. But stack overflow is not allowing me.
I hope that this will clarify my post further.

Matrix 1,2,3 how can i generate?

i want to control the creation of random numbers in this matrix :
Mp = floor(1+(10*rand(2,20)));
mp1 = sort(Mp,2);
i want to modify this code in order to have an output like this :
1 1 2 2 3 3 3 4 5 5 6 7 7 8 9 9 10 10 10 10
1 2 3 3 3 3 3 3 4 5 6 6 6 6 7 8 9 9 9 10
i have to fill each row with all the numbers going from 1 to 10 in an increasing order and the second matrix that counts the occurences of each number should be like this :
1 2 1 2 1 2 3 1 1 2 1 1 2 1 1 2 1 2 3 4
1 1 1 2 3 4 5 6 1 1 1 2 3 4 1 1 1 2 3 1
and the most tricky matrix that i'v been looking for since the last week is the third matrix that should skim through each row of the first matrix and returns the numbers of occurences of each number and the position of the last occcurence.here is an example of how the code should work. this example show the intended result after running through the first row of the first matrix.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (positions)
1 2
2 2
3 3
4 1
5 2
6 1
7 2
8 1
9 2
10 4
(numbers)
this example show the intended result after running through the second row of the first matrix.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (positions)
1 1 2
2 1 2
3 3 6
4 1 1
5 3
6 1 4
7 2 1
8 1 1
9 2 3
10 4
(numbers)
so the wanted matrix must be filled up with zeros from the beginning and each time after running through each row of the first matrix, we add the new result to the previous one...
I believe the following code does everything you asked for. If I didn't understand, you need to get a lot clearer in how you pose your question...
Note - I hard coded some values / sizes. In "real code" you would never do that, obviously.
% the bit of code that generates and sorts the initial matrix:
Mp = floor(1+(10*rand(2,20)));
mp1 = sort(Mp, 2);
clc
disp(mp1)
occCount = zeros(size(mp1));
for ii = 1:size(mp1,1)
for jj = 1:size(mp1,2)
if (jj == 1)
occCount(ii,jj) = 1;
else
if (mp1(ii,jj) == mp1(ii,jj-1))
occCount(ii,jj) = occCount(ii, jj-1) + 1;
else
occCount(ii,jj) = 1;
end
end
end
end
% this is the second matrix you asked for
disp(occCount)
% now the third:
big = zeros(10, 20);
for ii = 1:size(mp1,1)
for jj = 1:10
f = find(mp1(ii,:) == jj); % index of all of them
if numel(f) > 0
last = f(end);
n = numel(f);
big(jj, last) = big(jj, last) + n;
end
end
end
disp(big)
Please see if this is indeed what you had in mind.
The following code solves both the second and third matrix generation problems with a single loop. For clarity, the second matrix M2 is the 2-by-20 array in the example containing the cumulative occurrence count. The third matrix M3 is the sparse matrix of size 10-by-20 in the example that encodes the number and position of the last occurrence of each unique value. The code only loops over the rows, using accumarray to do most of the work. It is generalized to any size and content of mp1, as long as the rows are sorted first.
% data
mp1 = [1 1 2 2 3 3 3 4 5 5 6 7 7 8 9 9 10 10 10 10;
1 2 3 3 3 3 3 3 4 5 6 6 6 6 7 8 9 9 9 10]; % the example first matrix
nuniq = max(mp1(:));
% accumulate
M2 = zeros(size(mp1));
M3 = zeros(nuniq,size(mp1,2));
for ir=1:size(mp1,1),
cumSums = accumarray(mp1(ir,:)',1:size(mp1,2),[],#numel,[],true)';
segments = arrayfun(#(x)1:x,nonzeros(cumSums),'uni',false);
M2(ir,:) = [segments{:}];
countCoords = accumarray(mp1(ir,:)',1:size(mp1,2),[],#max,[],true);
[ii,jj] = find(countCoords);
nzinds = sub2ind(size(M3),ii,nonzeros(countCoords));
M3(nzinds) = M3(nzinds) + nonzeros(cumSums);
end
I won't print the outputs because they are a bit big for the answer, and the code is runnable as is.
NOTE: For new test data, I suggest using the commands Mp = randi(10,[2,20]); mp1 = sort(Mp,2);. Or based on your request to user2875617 and his response, ensure all numbers with mp1 = sort([repmat(1:10,2,1) randi(10,[2,10])],2); but that isn't really random...
EDIT: Error in code fixed.
I am editing the previous answer to check if it is fast when mp1 is large, and apparently it is:
N = 20000; M = 200; P = 100;
mp1 = sort([repmat(1:P, M, 1), ceil(P*rand(M,N-P))], 2);
tic
% Initialise output matrices
out1 = zeros(M, N); out2 = zeros(P, N);
for gg = 1:M
% Frequencies of each row
freqs(:, 1) = mp1(gg, [find(diff(mp1(gg, :))), end]);
freqs(:, 2) = histc(mp1(gg, :), freqs(:, 1));
cumfreqs = cumsum(freqs(:, 2));
k = 1;
for hh = 1:numel(freqs(:, 1))
out1(gg, k:cumfreqs(hh)) = 1:freqs(hh, 2);
out2(freqs(hh, 1), cumfreqs(hh)) = out2(freqs(hh, 1), cumfreqs(hh)) + freqs(hh, 2);
k = cumfreqs(hh) + 1;
end
end
toc

Efficiently generating unique pairs of integers

In MATLAB, I would like to generate n pairs of random integers in the range [1, m], where each pair is unique. For uniqueness, I consider the order of the numbers in the pair to be irrelevant such that [3, 10] is equal to [10, 3].
Also, each pair should consist of two distinct integers; i.e. [3, 4] is ok but [3, 3] would be rejected.
EDIT: Each possible pair should be chosen with equal likelihood.
(Obviously a constraint on the parameters is that n <= m(m-1)/2.)
I have been able to successfully do this when m is small, like so:
m = 500; n = 10; % setting parameters
A = ((1:m)'*ones(1, m)); % each column has the numbers 1 -> m
idxs1 = squareform(tril(A', -1))';
idxs2 = squareform(tril(A, -1))';
all_pairs = [idxs1, idxs2]; % this contains all possible pairs
idx_to_use = randperm( size(all_pairs, 1), n ); % choosing random n pairs
pairs = all_pairs(idx_to_use, :)
pairs =
254 414
247 334
111 146
207 297
45 390
229 411
9 16
75 395
12 338
25 442
However, the matrix A is of size m x m, meaning when m becomes large (e.g. upwards of 10,000), MATLAB runs out of memory.
I considered generating a load of random numbers randi(m, [n, 2]), and repeatedly rejecting the rows which repeated, but I was concerned about getting stuck in a loop when n was close to m(m-1)/2.
Is there an easier, cleaner way of generating unique pairs of distinct integers?
Easy, peasy, when viewed in the proper way.
You wish to generate n pairs of integers, [p,q], such that p and q lie in the interval [1,m], and p
How many possible pairs are there? The total number of pairs is just m*(m-1)/2. (I.e., the sum of the numbers from 1 to m-1.)
So we could generate n random integers in the range [1,m*(m-1)/2]. Randperm does this nicely. (Older matlab releases do not allow the second argument to randperm.)
k = randperm(m/2*(m-1),n);
(Note that I've written this expression with m in a funny way, dividing by 2 in perhaps a strange place. This avoids precision problems for some values of m near the upper limits.)
Now, if we associate each possible pair [p,q] with one of the integers in k, we can work backwards, from the integers generated in k, to a pair [p,q]. Thus the first few pairs in that list are:
{[1,2], [1,3], [2,3], [1,4], [2,4], [3,4], ..., [m-1,m]}
We can think of them as the elements in a strictly upper triangular array of size m by m, thus those elements above the main diagonal.
q = floor(sqrt(8*(k-1) + 1)/2 + 1/2);
p = k - q.*(q-1)/2;
See that these formulas recover p and q from the unrolled elements in k. We can convince ourselves that this does indeed work, but perhaps a simple way here is just this test:
k = 1:21;
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
[k;p;q]'
ans =
1 1 2
2 1 3
3 2 3
4 1 4
5 2 4
6 3 4
7 1 5
8 2 5
9 3 5
10 4 5
11 1 6
12 2 6
13 3 6
14 4 6
15 5 6
16 1 7
17 2 7
18 3 7
19 4 7
20 5 7
21 6 7
Another way of testing it is to show that all pairs get generated for a small case.
m = 5;
n = 10;
k = randperm(m/2*(m-1),n);
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
sortrows([p;q]',[2 1])
ans =
1 2
1 3
2 3
1 4
2 4
3 4
1 5
2 5
3 5
4 5
Yup, it looks like everything works perfectly. Now try it for some large numbers for m and n to test the time used.
tic
m = 1e6;
n = 100000;
k = randperm(m/2*(m-1),n);
q = floor(sqrt(8*(k-1) + 1)/2 + 3/2);
p = k - (q-1).*(q-2)/2;
toc
Elapsed time is 0.014689 seconds.
This scheme will work for m as large as roughly 1e8, before it fails due to precision errors in double precision. The exact limit should be m no larger than 134217728 before m/2*(m-1) exceeds 2^53. A nice feature is that no rejection for repeat pairs need be done.
This is more of a general approach rather then a matlab solution.
How about you do the following first you fill a vector like the following.
x[n] = rand()
x[n + 1] = x[n] + rand() %% where rand can be equal to 0.
Then you do the following again
x[n][y] = x[n][y] + rand() + 1
And if
x[n] == x[n+1]
You would make sure that the same pair is not already selected.
After you are done you can run a permutation algorithm on the matrix if you want them to be randomly spaced.
This approach will give you all the possibility or 2 integer pairs, and it runs in O(n) where n is the height of the matrix.
The following code does what you need:
n = 10000;
m = 500;
my_list = unique(sort(round(rand(n,2)*m),2),'rows');
my_list = my_list(find((my_list(:,1)==my_list(:,2))==0),:);
%temp = my_list; %In case you want to check what you initially generated.
while(size(my_list,1)~=n)
%my_list = unique([my_list;sort(round(rand(1,2)*m),2)],'rows');
%Changed as per #jucestain's suggestion.
my_list = unique([my_list;sort(round(rand((n-size(my_list,1)),2)*m),2)],'rows');
my_list = my_list(find((my_list(:,1)==my_list(:,2))==0),:);
end