Fast way to test whether n^2 + (n+1)^2 is perfect square - matlab

I am trying to program a code to test whether n^2 + (n+1)^2 is a perfect.
As i do not have much experience in programming, I only have Matlab at my disposal.
So far this is what I have tried
function [ Liste ] = testSquare(N)
if exist('NumberTheory')
load NumberTheory.mat
else
MaxT = 0;
end
if MaxT > N
return
elseif MaxT > 0
L = 1 + MaxT;
else
L = 1;
end
n = (L:N)'; % Makes a list of numbers from L to N
m = n.^2 + (n+1).^2; % Makes a list of numbers on the form A^2+(A+1)^2
P = dec2hex(m); % Converts this list to hexadecimal
Length = length(dec2hex(P(N,:))); %F inds the maximum number of digits in the hexidecimal number
Modulo = ['0','1','4','9']'; % Only numbers ending on 0,1,4 or 9 can be perfect squares in hex
[d1,~] = ismember(P(:,Length),Modulo); % Finds all numbers that end on 0,1,4 or 9
m = m(d1); % Removes all numbers not ending on 0,1,4 or 9
n = n(d1); % -------------------||-----------------------
mm = sqrt(m); % Takes the square root of all the possible squares
A = (floor(mm + 0.5).^2 == m); % Tests wheter these are actually squares
lA = length(A(A>0)); % Finds the number of such numbers
MaxT = N;
save NumberTheory.mat MaxT;
if lA>0
m = m(A); % makes a list of all the square numbers
n = n(A); % finds the corresponding n values
mm = mm(A); % Finds the squareroot values of m
fid = fopen('Tallteori.txt','wt'); % Writes everything to a simple text.file
for ii = 1:lA
fprintf(fid,'%20d %20d %20d\t',n(ii),m(ii),mm(ii));
fprintf(fid,'\n');
end
fclose(fid);
end
end
Which will write the squares with the corresponding n values to a file. Now I saw that using hexadecimal was a fast way to find perfect squares in C+, and tried to use this in matlab. However I am a tad unsure if this is the best approach.
The code above breaks down when m > 2^52 due to the hexadecimal conversion.
Is there an alternative way/faster to write all the perfect squares on the form n^2 + (n+1)^2 to a text file from 1 to N ?

There is a much faster way that doesn't even require testing. You need a bit of elementary number theory to find that way, but here goes:
If n² + (n+1)² is a perfect square, that means there is an m such that
m² = n² + (n+1)² = 2n² + 2n + 1
<=> 2m² = 4n² + 4n + 1 + 1
<=> 2m² = (2n+1)² + 1
<=> (2n+1)² - 2m² = -1
Equations of that type are easily solved, starting from the "smallest" (positive) solution
1² - 2*1² = -1
of
x² - 2y² = -1
corresponding to the number 1 + √2, you obtain all further solutions by multiplying that with a power of the primitive solution of
a² - 2b² = 1
which is (1 + √2)² = 3 + 2*√2.
Writing that in matrix form, you obtain all solutions of x² - 2y² = -1 as
|x_k| |3 4|^k |1|
|y_k| = |2 3| * |1|
and all x_k are necessarily odd, thus can be written as 2*n + 1.
The first few solutions (x,y) are
(1,1), (7,5), (41,29), (239,169)
corresponding to (n,m)
(0,1), (3,5), (20,29), (119,169)
You can get the next (n,m) solution pair via
(n_(k+1), m_(k+1)) = (3*n_k + 2*m_k + 1, 4*n_k + 3*m_k + 2)
starting from (n_0, m_0) = (0,1).
Quick Haskell code since I don't speak MatLab:
Prelude> let next (n,m) = (3*n + 2*m + 1, 4*n + 3*m + 2) in take 20 $ iterate next (0,1)
[(0,1),(3,5),(20,29),(119,169),(696,985),(4059,5741),(23660,33461),(137903,195025)
,(803760,1136689),(4684659,6625109),(27304196,38613965),(159140519,225058681)
,(927538920,1311738121),(5406093003,7645370045),(31509019100,44560482149)
,(183648021599,259717522849),(1070379110496,1513744654945),(6238626641379,8822750406821)
,(36361380737780,51422757785981),(211929657785303,299713796309065)]
Prelude> map (\(n,m) -> (n^2 + (n+1)^2 - m^2)) it
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
Edit by EitanT:
Here's the MATLAB code to calculate the first N numbers:
res = zeros(1, N);
nm = [0, 1];
for k = 1:N
nm = nm * [3 4; 2 3] + [1, 2];
res(k) = nm(1);
end
The resulting array res should hold the values of n that satisfy the condition of the perfect square.

Related

Take a random draw of all possible pairs of indices in Matlab

Consider a Matlab matrix B which lists all possible unordered pairs (without repetitions) from [1 2 ... n]. For example, if n=4,
B=[1 2;
1 3;
1 4;
2 3;
2 4;
3 4]
Note that B has size n(n-1)/2 x 2
I want to take a random draw of m rows from B and store them in a matrix C. Continuing the example above, I could do that as
m=2;
C=B(randi([1 size(B,1)],m,1),:);
However, in my actual case, n=371293. Hence, I cannot create B and, then, run the code above to obtain C. This is because storing B would require a huge amount of memory.
Could you advise on how I could proceed to create C, without having to first store B? Comments on a different question suggest to
Draw at random m integers between 1 and n(n-1)/2.
I=randi([1 n*(n-1)/2],m,1);
Use ind2sub to obtain C.
Here, I'm struggling to implement the second step.
Thanks to the comments below, I wrote this
n=4;
m=10;
coord=NaN(m,2);
R= randi([1 n^2],m,1);
for i=1:m
[cr, cc]=ind2sub([n,n],R(i));
if cr>cc
coord(i,1)=cc;
coord(i,2)=cr;
elseif cr<cc
coord(i,1)=cr;
coord(i,2)=cc;
end
end
coord(any(isnan(coord),2),:) = []; %delete NaN rows from coord
I guess there are more efficient ways to implement the same thing.
You can use the function named myind2ind in this post to take random rows of all possible unordered pairs without generating all of them.
function [R , C] = myind2ind(ii, N)
jj = N * (N - 1) / 2 + 1 - ii;
r = (1 + sqrt(8 * jj)) / 2;
R = N -floor(r);
idx_first = (floor(r + 1) .* floor(r)) / 2;
C = idx_first-jj + R + 1;
end
I=randi([1 n*(n-1)/2],m,1);
[C1 C2] = myind2ind (I, n);
If you look at the odds, for i=1:n-1, the number of combinations where the first value is equal to i is (n-i) and the total number of cominations is n*(n-1)/2. You can use this law to generate the first column of C. The values of the second column of C can then be generated randomly as integers uniformly distributed in the range [i+1, n]. Here is a code that performs the desired tasks:
clc; clear all; close all;
% Parameters
n = 371293; m = 10;
% Generation of C
R = rand(m,1);
C = zeros(m,2);
s = 0;
t = n*(n-1)/2;
for i=1:n-1
if (i<n-1)
ind_i = R>=s/t & R<(s+n-i)/t;
else % To avoid rounding errors for n>>1, we impose (s+n-i)=t at the last iteration (R<(s+n-i)/t=1 always true)
ind_i = R>=s/t;
end
C(ind_i,1) = i;
C(ind_i,2) = randi([i+1,n],sum(ind_i),1);
s = s+n-i;
end
% Display
C
Output:
C =
84333 266452
46609 223000
176395 328914
84865 94391
104444 227034
221905 302546
227497 335959
188486 344305
164789 266497
153603 354932
Good luck!

Generate cell with random pairs without repetitions

How to generate a sequence of random pairs without repeating pairs?
The following code already generates the pairs, but does not avoid repetitions:
for k=1:8
Comb=[randi([-15,15]) ; randi([-15,15])];
T{1,k}=Comb;
end
When running I got:
T= [-3;10] [5;2] [1;-5] [10;9] [-4;-9] [-5;-9] [3;1] [-3;10]
The pair [-3,10] is repeated, which cannot happen.
PS : The entries can be positive or negative.
Is there any built in function for this? Any sugestion to solve this?
If you have the Statistics Toolbox, you can use randsample to sample 8 numbers from 1 to 31^2 (where 31 is the population size), without replacement, and then "unpack" each obtained number into the two components of a pair:
s = -15:15; % population
M = 8; % desired number of samples
N = numel(s); % population size
y = randsample(N^2, M); % sample without replacement
result = s([ceil(y/N) mod(y-1, N)+1]); % unpack pair and index into population
Example run:
result =
14 1
-5 7
13 -8
15 4
-6 -7
-6 15
2 3
9 6
You can use ind2sub:
n = 15;
m = 8;
[x y]=ind2sub([n n],randperm(n*n,m));
Two possibilities:
1.
M = nchoosek(1:15, 2);
T = datasample(M, 8, 'replace', false);
2.
T = zeros(8,2);
k = 1;
while (k <= 8)
t = randi(15, [1,2]);
b1 = (T(:,1) == t(1));
b2 = (T(:,2) == t(2));
if ~any(b1 & b2)
T(k,:) = t;
k = k + 1;
end
end
The first method is probably faster but takes up more memory and may not be practicable for very large numbers (ex: if instead of 15, the max was 50000), in which case you have to go with 2.

Matlab : Binary to decimal conversion using symbols from clustering algorithm

q = 2;
k= 2^q;
x1 = [0.0975000000000000, 0.980987500000000, -0.924672950312500, -0.710040130079246];
for i = 1 : length(x1)
[idx_centers,location] = kmeans(x1',q);
end
temp = idx_centers;
for i = 1 : length(x1)
if temp(i)== 2
idx_centers(i) = 0;
end
BinaryCode_KMeans(i) = idx_centers(i); % output is say [0,0,1,1];
end
strng = num2str(BinaryCode_KMeans);
DecX = bin2dec(strng);
In the above code snippet, I want to express the binary string to its decimal equivalent where the binary string is obtained from kmeans clustering. The decimal equivalent should either be 1,2,3, or 4 i.e., k = 2^q when q=2.
But sometimes after conversion, the decimal equivalent is 12 because for a 4 bit binary code we get decimal numbers in 1 to 16 or 0 -- 15. the number of elements in x1 can vary and can be less than or greater than k. What should I do so that I can always get the decimal equivalent of the binary code within k for any value of q?
First of, there is no need to run kmeans multiple times, it will calculate the cluster centers using a single run. Note that, the code below tries to find a mapping between the clustering results and n the number of samples. There are three ways in the code below to encode this information.
clear
clc
q = 2;
k= 2^q;
n = 4;
x1 = rand(n,1);
fprintf('x1 = [ '); fprintf('%d ', x1); fprintf(']\n');
[idx_centers, location] = kmeans(x1, q);
fprintf('idx_centers = [ '); fprintf('%d ', idx_centers); fprintf(']\n');
for i = 1:q
idx_centers(idx_centers == i) = i-1;
end
fprintf('idx_centers = [ '); fprintf('%d ', idx_centers); fprintf(']\n');
string = num2str(idx_centers');
% Original decimal value
DecX = bin2dec(string);
fprintf('0 to (2^n) - 1: %d\n', DecX);
% Reduced space decimal value
% Ignoring the 0/1 order as [ 1 1 0 0 ]
% would be the same as [ 0 0 1 1 ]
if DecX >= (2^n)/2
complement = bitget(bitcmp(int64(DecX)),n:-1:1);
DecX = bin2dec(num2str(complement));
end
fprintf('0 to ((2^n)/2) - 1: %d\n', DecX);
% Minimal Decimal value based on the number of samples
% in the 0's cluster which is in the range of 0 to n-1
fprintf('0 to n - 1: %d\n', numel(find(idx_centers == 0)));
Hint: If you change the q to more than 2, the code will not work because bin2dec only accepts zeros and ones. In case of having more than 2 clusters, you need to elaborate the code and use multidimensional arrays to store the pairwise clustering results.

How to randomly select multiple small and non-overlapping matrices from a large matrix?

Let's say I've a large N x M -sized matrix A (e.g. 1000 x 1000). Selecting k random elements without replacement from A is relatively straightforward in MATLAB:
A = rand(1000,1000); % Generate random data
k = 5; % Number of elements to be sampled
sizeA = numel(A); % Number of elements in A
idx = randperm(sizeA); % Random permutation
B = A(idx(1:k)); % Random selection of k elements from A
However, I'm looking for a way to expand the above concept so that I could randomly select k non-overlapping n x m -sized sub-matrices (e.g. 5 x 5) from A. What would be the most convenient way to achieve this? I'd very much appreciate any help!
This probably isn't the most efficient way to do this. I'm sure if I (or somebody else) gave it more thought there would be a better way but it should help you get started.
First I take the original idx(1:k) and reshape it into a 3D matrix reshape(idx(1:k), 1, 1, k). Then I extend it to the length required, padding with zeros, idx(k, k, 1) = 0; % Extend padding with zeros and lastly I use 2 for loops to create the correct indices
for n = 1:k
for m = 1:k
idx(m, 1:k, n) = size(A)*(m - 1) + idx(1, 1, n):size(A)*(m - 1) + idx(1, 1, n) + k - 1;
end
end
The complete script built onto the end of yours
A = rand(1000, 1000);
k = 5;
idx = randperm(numel(A));
B = A(idx(1:k));
idx = reshape(idx(1:k), 1, 1, k);
idx(k, k, 1) = 0; % Extend padding with zeros
for n = 1:k
for m = 1:k
idx(m, 1:k, n) = size(A)*(m - 1) + idx(1, 1, n):size(A)*(m - 1) + idx(1, 1, n) + k - 1;
end
end
C = A(idx);

Shorten this in Matlab

Let x = [1,...,t] be a vector with t components and A and P arrays. I asked myself whether there is any chance to shorten this, as it looks very cumbersome:
for n = 1:t
for m = 1:n
H(n,m) = A(n,m) + x(n) * P(n,m)
end
end
My suggestion: bsxfun(#times,x,P) + A;
e.g.
A = rand(3);
P = rand(3);
x = rand(3,1);
for n = 1:3
for m = 1:3
H(n,m) = A(n,m) + x(n) * P(n,m);
end
end
H2 = bsxfun(#times,x,P) + A;
%//Check that they're the same
all(H(:) == H2(:))
returns
ans = 1
EDIT:
Amro is right! To make the second loop is dependent on the first use tril:
H2 = tril(bsxfun(#times,x,P) + A);
Are the matrices square btw because that also creates other problems
tril(A + P.*repmat(x',1,t))
EDIT. This is for when x is row vector.
If x is a column vector, then use tril(A + P.*repmat(x,t,1))
If your example code is correct, then H(i,j) = 0 for any j > i, e.g. X(1,2).
For t = 3 for example, you would have.
H =
'A(1,1) + x(1) * P(1,1)' [] []
'A(2,1) + x(2) * P(2,1)' 'A(2,2) + x(2) * P(2,2)' []
'A(3,1) + x(3) * P(3,1)' 'A(3,2) + x(3) * P(3,2)' 'A(3,3) + x(3) * P(3,3)'
Like I pointed out in the comments, unless it was a typo mistake, the second for-loop counter depends on that of the first for-loop...
In case it was intentional, I came up with the following solution:
% some random data
t = 10;
x = (1:t)';
A = rand(t,t);
P = rand(t,t);
% double for-loop
H = zeros(t,t);
for n = 1:t
for m = 1:n
H(n,m) = A(n,m) + x(n) * P(n,m);
end
end
% vectorized using linear-indexing
[a,b] = ndgrid(1:t,1:t);
idx = sub2ind([t t], nonzeros(tril(a)), nonzeros(tril(b)));
xidx = nonzeros(tril(a));
HH = zeros(t);
HH(tril(true(t))) = A(idx) + x(xidx).*P(idx);
% check the results are the same
assert(isequal(H,HH))
I like #Dan's solution better. The only advantage here is that I do not compute unnecessary values (since the upper half of the matrix is zeros), while the other solution computes the full matrix and then cut back the extra stuff.
A good start would be
H = A + x*P
This may not be a working solution, you'll have to check conformability of arrays and vectors, and make sure that you're using the correct multiplication, but this should be enough to point you in the right direction. If you're new to Matlab be aware that vectors can be either 1xn or nx1, ie row and column vectors are different species unlike in so many programming languages. If x isn't what you want on the rhs, you may want its transpose, x' in Matlab.
Matlab is, from one point of view, an array language, explicit loops are often unnecessary and frequently not even a good way to go.
Since the range for second loop is 1:n, you can take the lower triangle parts of matrices A and P for calculation
H = bsxfun(#times,x(:),tril(P)) + tril(A);