Output 1, 0.5, or 0 depending if a matrix elements are prime, 1, or neither - matlab

I am sending a matrix to my function modifikuj, where I want to replace the elements of the matrix with:
1 if element is a prime number
0 if element is a composite number
0.5 if element is 1
I dont understand why it is not working. I just started with MATLAB, and I created this function:
function B = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j))
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
With
A = [1,2;3,4];
D = modifikuj(A);
D should be:
D=[0.5, 1; 1 0];

In MATLAB you'll find you can often avoid loops, and there's plenty of built in functions to ease your path. Unless this is a coding exercise where you have to use a prescribed method, I'd do the following one-liner to get your desired result:
D = isprime( A ) + 0.5*( A == 1 );
This relies on two simple tests:
isprime( A ) % 1 if prime, 0 if not prime
A == 1 % 1 if == 1, 0 otherwise
Multiplying the 2nd test by 0.5 gives your desired condition for when the value is 1, since it will also return 0 for the isprime test.

You are not returning anything from the function. The return value is supposed to be 'B' according to your code but this is not set. Change it to A.
You are looping k until A(i,j) which is always divisible by itself, loop to A(i,j)-1
With the code below I get [0.5,1;1,0].
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j)-1)
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end

In addition to #EuanSmith's answer. You can also use the in built matlab function in order to determine if a number is prime or not.
The following code will give you the desired output:
A = [1,2;3,4];
A(A==1) = 0.5; %replace 1 number with 0.5
A(isprime(A)) = 1; %replace prime number with 1
A(~ismember(A,[0.5,1])) = 0; %replace composite number with 0
I've made the assumption that the matrice contains only integer.
If you only want to learn, you can also preserve the for loop with some improvement since the function mod can take more than 1 divisor as input:
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
k = A(i,j);
if (k == 1)
A(i,j) = 0.5;
else
if all(mod(k,2:k-1)) %check each modulo at the same time.
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
And you can still improve the prime detection:
2 is the only even number to test.
number bigger than A(i,j)/2 are useless
so instead of all(mod(k,2:k-1)) you can use all(mod(k,[2,3:2:k/2]))
Note also that the function isprime is a way more efficient primality test since it use the probabilistic Miller-Rabin algorithme.

Related

Program to find prime numbers in MATLAB

I wrote some code to display the prime numbers between 2 and a user-chosen number, following the pseudocode on wikipedia. I am not sure why this does not work, as I have the increments correct following Erastothenes' Sieve. Please help me.
I have tried changing the bounds but this did not work.
There are no errors, but it returns the wrong output. If I enter 10, it returns 2, 3, 4, 5, 6, 7, 8, 9, 10.
n=input("Enter an upper limit: ");
nums= 2:n;
p=2;
for i = p:sqrt(n)
for j = (i^2):i:sqrt(n)
nums(j) = 0;
end
end
for k = 1:n-1
if nums(k) ~= 0
disp(nums(k))
end
end
You can use the primes function in MATLAB for this
N = 10; % upper limit
p = primes(N); % List of all primes up to (and including) N
With one step less automation, you could use another in-built isprime
p = 1:N; % List of all numbers up to N
p( ~isprime( p ) ) = []; % Remove non-primes
Finally without using built-ins, we can address your code!
I assume you're referring to this pseudocode for the Sieve of Eratosthenes on Wikipedia.
Input: an integer n > 1.
Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n:
if A[i] is true:
for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n:
A[j] := false.
Output: all i such that A[i] is true.
I'll follow it step by step, pointing out differences to your code:
n = 10;
A = [false; true(n-1,1)]; % array of true Booleans, first element (1) is not prime
% But I've included a first element to make indexing easier.
% In your code, you were using index 'i' which was incorrect, as your array started at 2.
% Two options: (1) take my approach and pad the array
% (2) take your approach and using indices i-1 and j-1
for ii = 2:sqrt(n)
if A(ii) == true % YOU WERE MISSING THIS STEP!
for jj = ii^2:ii:n % YOU ONLY LOOPED UNTIL SQRT(n)!
A(jj) = false;
end
end
end
p = find(A);
disp(p)
This outputs the expected values.
Note that, at the end of the manual looping method, A is equivalent to isprime(1:n), mirroring my earlier suggestions.
There is two mistakes in your code:
The multiple should be check until n and not sqrt(n)
Since your nums vector start with 2 and not 1, if you want to
access the right value you need to use nums(j-1) = 0
So:
n=100
nums= 2:n;
p=2;
for i = p:sqrt(n)
for j = (i^2):i:n
nums(j-1) = 0;
end
end
for k = 1:n-1
if nums(k) ~= 0
disp(nums(k))
end
end
Noticed that you can skip one for loop using a modulo, it's probably not faster than the previous solution since this code create a logical index that include each prime that already been found.
n = 100
nums= 2:n;
for i = 2:sqrt(n)
nums(mod(nums,i)==0 & nums != i) = [];
end
nums.'
I simply delete the value in nums that can be divided by x but not x.

Nested for loop error or indexing error in MATLAB

I have created this code from scratch. I want to make a plot and/or histogram of my "Observed" and "State" (these are 2 matrices). Some problem occurs at the 200th iteration, where my State matrix just becomes all 0's, there is no data being input into the State matrix. Can anyone troubleshoot the code? My possible states are {1,2,3}.
UPDATE:
When I adjust my n value, it adjusts how much of length T it will fill. So, n=5, only runs for 1/5 of T and n=1, run for entire length of T. I need an nxT matrix at the end (5X1000). The problem lies in the way I setup my for loops.
I still cannot solve the error though.
%Initialize A,pi,T
N = 3; # of states
%A is transition prob matrix
A = [.99,.005,.005;.005,.990,.005;.005,.005,.990];
%pi is initial state vector
pi = [1/3,1/3,1/3];
%T is # of observations per simulation
T = 1000;
%n is # of simulations
n = 5;
%Allocate space for the state matrix
State = zeros(n,T);
Observe = zeros(n,T);
%Create dummy emission matrix, must be row stochastic
B = ones(n,T)./T;
%loop over # of simulations
for i=1:1:n
x = rand(1);
if x <= (1/3)
State(i,1) = 1;
elseif x > (1/3) && x <= (2/3)
State(i,1) = 2;
else
State(i,1) = 3;
end
if State(i,1) == 1
b = -1;
elseif State(i,1) == 2
b = 0;
else
b = 1;
end
Observe(i,1)= normrnd(b,1);
for k=2:1:T
%Possible state 1,2,3
State(k) = randsample(N, 1, true, A(State(k-1),:));
if State == 1
c = -1;
elseif State == 2
c = 0;
else
c = 1;
end
Observe(i,k)= normrnd(c,1);
end
end
State(k) = randsample(N, 1, true, A(State(k-1),:));
This line is missing index (i) in position 1 inside State(k-1). It should be:
State(i,k) = randsample(N, 1, true, A(State(i,k-1),:));

Storing non-zero integers from one matrix into another

I'm attempting to create a loop that reads through a matrix (A) and stores the non-zero values into a new matrix (w). I'm not sure what is wrong with my code.
function [d,w] = matrix_check(A)
[nrow ncol] = size(A);
total = 0;
for i = 1:nrow
for j = 1:ncol
if A(i,j) ~= 0
total = total + 1;
end
end
end
d = total;
w = [];
for i = 1:nrow
for j = 1:ncol
if A(i,j) ~= 0
w = [A(i,j);w];
end
end
end
The second loop is not working (at at least it is not printing out the results of w).
You can use nonzeros and nnz:
w = flipud(nonzeros(A)); %// flipud to achieve the same order as in your code
d = nnz(A);
The second loop is working. I'm guessing you're doing:
>> matrix_check(A)
And not:
>> [d, w] = matrix_check(A)
MATLAB will only return the first output unless otherwise specified.
As an aside, you can accomplish your task utilizing MATLAB's logical indexing and take advantage of the (much faster, usually) array operations rather than loops.
d = sum(sum(A ~= 0));
w = A(A ~= 0);

Matlab programming error

I am trying out the questions in programming assignment of Coursera course on Matlab programming as an exercise. This is for my self-study.
Question:
Write a function called classify that takes one input argument x. That
argument will have no more than two dimensions. If x is an empty
matrix, the function returns -1. If x is a scalar, it returns 0. If x
is a vector, it returns 1. Finally, if x is none of these, it returns
2. Do not use the built-in functions isempty, isscalar, or isvector.
My code snippet:
function num = classify(x)
num = -1;
if(x == 3.14159265358979)
num = 0;
elseif(size(x, 2) == 3)
num = -1;
end
end
I got the below result on Matlab.
Problem 4 (classify):
Feedback: Your function performed correctly for argument(s) []
Feedback: Your function performed correctly for argument(s) zeros(1,0)
Feedback: Your function performed correctly for argument(s) zeros(0,4)
Feedback: Your function performed correctly for argument(s) 3.14159265358979
Feedback: Your function made an error for argument(s) [1 2 3]
Am I doing something wrong for arguments [1 2 3]?
If all you want is the code, I'll provide you with the answer, but I suggest you sit down and try to understand how and why this codes solves the problem, I'm guessing you want to learn something from it. Well, here's the code:
function [num] = classify(x)
if numel(x) == 0
num = -1;
return
end
num = sum(size(x) > 1);
end
You can most easily check if x is empty or a scalar by counting the number of elements (i.e. use the numel function). Then to determine if it is a vector or a higher dimensional matrix you need to check if the number of dimensions is less than 3 (this is because ndims returns 2 for both 1D and 2D matrices) and also verify that at least one of the first two dimensions has a size of 1:
function num = classify(x)
n = numel(x);
if n < 2
num = n-1;
else
if ndims(x) < 3 && any(size(x) == 1)
num = 1;
else
num = 2;
end
end
end
You should aim to write a generic function, your function would not work for example for any scalar input than pi.
Use the size function to determine the dimensions of the input, for example:
>> size([])
ans = 0 0
>> size(5)
ans = 1 1
>> size([5 6 7])
ans = 1 3
>> size([5;6;7])
ans = 3 1
Based on this, your function could looke like this:
function [num] = classify(x)
s = size(x);
if s == [0 0]
num = -1;
elseif s == [1 1]
num = 0;
elseif sort(s) == [1 3]
num = 1;
else
num = 2;
end
end
Yes, you tring to compare an array with a float.
It allows to do that (programaticalyl wrong) thing for [] because the array is empty
And for zeros, because the array is empty again: in the first case 0 columns, and in the second 0 rows
function i=classify(x)
[m, n]=size(x);
if n==1 && m==1
i=0;
elseif (m==0 && n==0)|| (m>=1 && n==0) || (m==0 && n>=1)
i=-1;
elseif (n>=1 && m==1) || (n==1 && m>=1)
i=1;
else i=2;
end
function y=classify(x)
[a b]=size(x);
%check for empty matrix
% Do not forget that an empty matrix can be size a x 0 or 0x a, where a can be
% arbitrary number
if (a>0)&&(b==0)||(a==0)&&(b>0)||(a==0)&&(b==0)
y=(-1);
%check for scalar
elseif (a==1)&&(b==1)
y=0;
%check for vector
elseif (a>=1)&&(b==1)||(a==1)&&(b>=1)
y=1;
%other case
else
y=2;
end

Counting Number of Specific Outputs of a Function

If I have a matrix and I want to apply a function to each row of the matrix. This function has three possible outputs, either x = 0, x = 1, or x > 0. There's a couple things I'm running into trouble with...
1) The cases that output x = 1 or x > 0 are different and I'm not sure how to differentiate between the two when writing my script.
2) My function isn't counting correctly? I think this might be a problem with how I have my loop set up?
This is what I've come up with. Logically, I feel like this should work (except for the hiccup w/ the first problem I've stated)
[m n] = size(matrix);
a = 0; b = 0; c = 0;
for i = 1 : m
x(i) = function(matrix(m,:));
if x > 0
a = a + 1;
end
if x == 0
b = b + 1;
end
if x == 1
c = c + 1;
end
end
First you probably have an error in line 4. It probably should be i instead of m.
x(i) = function(matrix(i,:));
You can calculate a, b and c out of the loop:
a = sum(x>0);
b = sum(x==0);
c = sum(x==1);
If you want to distinguish x==1 and x>0 then may be with sum(xor(x==1,x>0)).
Also you may have problem with precision error when comparing double values with 0 and 1.