Creating a Huffman Code from Markov Chain - matlab

I have the following probability transition matrix with each row corresponding to letters A, B, C, and D. I am trying to write a Huffman code for A, B, C, and D using these transition probabilities. I tried both by hand and in Matlab but I am confused whether or not you would make the code for AA, AB, AD, BB, ... etc or somehow account for all the probabilities and just find a code for A, B, C, and D. I do not think that this Matlab code gives the codes I am looking for. Any suggestions would be great.
T=[0.7 0.2 0 0.1;
0 0.8 0 0.2;
0.7 0.1 0.2 0;
0 0 0.6 0.4] %Probability Transition Matrix
p1 = [.7 .2 0 0.1];
p2 = [0 0.8 0 0.2];
p3 = [0.7 0.1 0.2 0];
p4 = [0 0 0.6 0.4];
%Create a Huffman dictionary based on the symbols and their probabilities.
dict1 = huffmandict(symbols,p1);
dict2 = huffmandict(symbols,p2);
dict3 = huffmandict(symbols,p3);
dict4 = huffmandict(symbols,p4);

You would have four codes, as you are constructing them, where the code used for the next symbol is selected by the previous symbol. (The first symbol would simply be sent as is.)
Note that only four symbols, or really two or three for each of your codes, is not much for Huffman coding to work with. In fact, there is only one possible Huffman code for each of the two or three symbol cases.

Related

How to do multiplication for two 4-bit numbers treating them as polynomials in MATLAB

I am simulating a mini AES encryption/decryption algorithm using MATLAB. For this I need to multiply two 4-bit numbers while treating them as polynomials. It goes though some stages, that are, converting to polynomials, multiply the two polynomials, polynomial reduction to lower power if needed using a predefined irreducible polynomial. Then converting back to 4-bit format.
For instance, multiplying 1011⊗ 0111 is analogous to x3+x+1 ⊗ x2+x+1 The ans is x5+x4+1 has of a power of 5 then you need to reduce it by dividing on the predefined polynomial x4+x+1. The answer will be x2 that is 0100.
I know that there are some functions in MATLAB doing polynomial multiplications but they are kind of general and need some specific function or method to do this.
Many thanks in advance!
Polynomial multiplication/division is the same as convolution/deconvolution of their coefficients. Then mod(...,2) is applied to the results.
I'm not quite sure that this two-step process is correct for GF; please try with some other polynomials have to see if the results are what you expect:
x = [1 0 1 1];
y = [0 1 1 1];
product = conv(x, y);
product = mod(product ,2);
divider = [1 0 0 1 1];
[~, remainder] = deconv(product, divider);
remainder = mod(remainder, 2);
This gives
product =
0 1 1 0 0 0 1
remainder =
0 0 0 0 1 0 0

Matlab - second derivative of data

Let's say we have
[x]=[0.1 0.2 0.3 0.4]
[y]=[0.25 0.30 0.40 0.55]
y1=diff(y)./diff(x)
y2=diff(y1)./diff(x)
And the result I get is
Matrix dimensions must agree
How do I solve this problem?
I redirect you towards this documentation. When you use the diff function, it will actually return you a vector with m-1 (m being its length), since what it does is output this:
diff(y1) = [y1(2)-y1(1) y1(3)-y1(2) ... y1(m)-y(m-1)]
As you can see, you will loose one value, and thus explaining your error. When you do your last line, it cannot divide diff(y1) by diff(x) since diff(y1) is equal to a vector of length 2 and diff(x) is equal to a vector of length 3.
Depending on what you want to do, you can change the code to the following :
[x]=[0.1 0.2 0.3 0.4]
[y]=[0.25 0.30 0.40 0.55]
y1=diff(y)./diff(x)
y2=diff(y1)./diff(x(1:end-1))
If you want to approximate the derivate of y, I really suggest you to take a look at the example in the page I linked. The matlab documentation always gives examples on how to use their functions, so go take a look. According to the documentation, if you want to calculate the partial derivate of the vector y, you need the step of your x vector.
x=[0.1 0.2 0.3 0.4]
y=[0.25 0.30 0.40 0.55]
x_step = 0.1
y1=diff(y)./x_step
y2=diff(y1)./x_step
x=[0.1 0.2 0.3 0.4] ;
y=[0.25 0.30 0.40 0.55] ;
dy = gradient(y)./gradient(x) ;
d2y = gradient(dy)./gradient(x) ;

Curve fitting equations involving integrals in MATLAB

I have an equation that I am trying to fit to some experimental data. In the past I have used lsqcurvefit and passed in the experimental data, and the function that describes my fitted data. E.g.
model = #(p,x) exp(-p(1).*x);
startingVals = 0.5;
lsqcurvefit(model,startingVals,expData_x,exptData_y)
This would work perfectly with MATLAB returning the value of p that most closely fits my data. Internally I guess it is tweaking the values of p a smart way to minimise the sum of the differences squared.
Now I have a model that is not analytical and want to find the closest fitting B. An example is:
model = integral(#(v)besselj(0,x.*v.*B), 0, 40);
(just an example, maybe it can be solved analytically but my one definitively cant).
So to calculate the model I put in a trial version of B, and it calculates the function for each x. What I have been doing so far is calulating the model for a series of trial B terms, eg B = 1:1:10. This would give me 10 vectors each one with a different set of model points. I would then just run script which finds the smallest residual from each model calculation minus the experimental data.
This seems to work okay but now I am comming to an equation with more than one fitting term. For instance
model = integral(#(v)(C.*D).*besselj(0,x.*v.*B).^(E), 0, 40);
I now may want to find the best fitting values of B, C, D and E. My method would still work but there would be a crazy amount of experimental trials generated for instance looping through 10 values of each would be 10,000 individual curves generated.
Is my method fine or am I missing out on a much easier way to fit these kinds of functions?
Thanks
edit: Working code thanks to David.
Note that sometimes lsqcurvefit comes back with complex numbers but that is another issue. Obviously real data wont be a perfect fit but I had no idea you can pass such functions to lsqcurvefit.
A = 0.2; %input variables to 'solve' for later
B = 0.3;
C = 0.4;
D = 0.5;
x = logspace(-2,2,200); %x data
options = optimset('MaxFunEvals', 200,'MaxIter', 200,'TolFun',1e-10,'Display','off');
genData = arrayfun(#(x) integral(#(v) A.*B.*besselj(0,x.*v.*C).^D, 0, 40),x); %generate some data
genData = real(genData);
model = #(p,x) real(arrayfun(#(x) integral(#(v) p(1).*p(2).*besselj(0,x.*v.*p(3)).^p(4), 0, 40),x));
startingVals = [0.5 0.5 0.5 0.5]; %guess values
lb = [0.1 0.1 0.1 0.1]; %lower bound
ub = [1 1 1 1]; %upper bound
[p] = lsqcurvefit(model,startingVals,x,genData,lb,ub,options); %do the fit, takes a while
fitData = real(arrayfun(#(x) integral(#(v) p(1).*p(2).*besselj(0,x.*v.*p(3)).^p(4), 0, 40),x)); %regenrate data based on fitted values
semilogx(x,genData,'ro')
hold on
semilogx(x,fitData,'b')
This should let lsqcurvefit be able to work on model:
model=#(p,x) arrayfun(#(x) integral(#(v) p(1).*p(2).*besselj(0,x.*v.*p(3)).^p(4), 0, 40),x);
however I made up some coefficients B, C, D and E and performance isn't very good. I'm not sure whether it's because I picked bad numbers or whether it is a slow method.

Matrix as a 2D probability distribution: get the central moments

I have got a matrix which gives me a 2-dimensional discrete distribution (N²->R) in Matlab.
Are there built-in functions in Matlab (R2011b, with the statistic toolbox) giving the central moments and the mean? If they exist for functions of (R²->R) it is fine too. Otherwise I will have to build them myself, but I don't want to reinvent the wheel.
Thank you
A quick look and I couldn't turn up any functions, though this isn't a fact by any means.
However, working it out from scratch, and assuming you mean a matrix such as:
% x=1 x=2 x=3
P = [ 0.1 0.2 0.1 % y = 1
0.1 0.1 0.2 % y = 2
0.0 0.0 0.2 ] % y = 3
And you mean that this describes the joint discrete distribution (joint probability mass function). That is, the entry at (X,Y) contains the probability of (X,Y) occurring.
I'm also assuming by your use of N in mathematical notation means the natural numbers. If so, then you can use the following code.
Mean:
meanX = sum(P,1) * (1:size(P,2))';
meanY = sum(P,2)' * (1:size(P,1))';
For the central moment K,L (K correspnding to X and L corresponding to Y):
[X,Y] = meshgrid(1:size(P,2),1:size(P,1));
integrandXY_KL = (X - meanX).^K .* (Y-meanY).^L .* P;
momentXY_KL = sum(integrandXY_KL(:));
And you can generalize it further if the values of X are arbitrary (and not just natural numbers) as follows. If Xvals = [ 1 2 4 ] and Yvals = [ 4 5 6 ]. All of the above still works, you just replace all occurences of 1:size(P,2) with Xvals and all occurences of 1:size(P,1) with Yvals.

conditional generation of random numbers using matlab

I have a function that generates normal random number matrix having normal distribution using normrnd.
values(vvvv)= normrnd(0,0.2);
The output is from round1 is:
ans =
0.0210 0.1445 0.5171 -0.1334 0.0375 -0.0165 Inf -0.3866 -0.0878 -0.3589
The output from round 2 is:
ans =
0.0667 0.0783 0.0903 -0.0261 0.0367 -0.0952 0.1724 -0.2723 Inf Inf
The output from round 3 is:
ans =
0.4047 -0.4517 0.4459 0.0675 0.2000 -0.3328 -0.1180 -0.0556 0.0845 Inf
the function will be repeated 20 times.
It is obvious that the function is completely random. What I seek is to add a condition.
What I need is: if any entry has a value between 0.2 and 0.3. that value will be fixed in the next rounds. Only the remaining entries will be subjected to change using the function rand.
I have found the rng(sd) which seeds the random number generator using the nonnegative integer sd so that rand, randi, and randn produce a predictable sequence of numbers.
How to set custom seed for pseudo-random number generator
but how to make several entries of the matrix only effected!!
Another problem: seems that rng is not available for matlab r2009
How to get something similar without entering in the complication of probability & statistics
You can do this more directly than actually generating all these matrices, and it's pretty easy to do so, by thinking about the distribution of the final output.
The probability of a random variable distributed by N(0, .2) lying between .2 and .3 is p ~= .092.
Call the random variable of the final output of your matrix X, where you do this n (20) times. Then either (a) X lies between .2 and .3 and you stopped early, or (b) you didn't draw a number between .2 and .3 in the first n-1 draws and so you went with whatever you got on the nth draw.
The probability of (b) happening is just b=(1-p)^(n-1): the independent events of drawing outside [.2, .3], which have probability 1-p, happend n-1 times. Therefore the probability of (a) is 1-b.
If (b) happened, you just draw a number from normrnd. If (a) happened, you need the value of a normal variable, conditional on its being between .2 and .3. One way to do this is to find the cdf values for .2 and .3, draw uniformly from the range between there, and then use the inverse cdf to get back the original number.
Code that does this:
mu = 0;
sigma = .2;
upper = .3;
lower = .2;
n = 20;
sz = 15;
cdf_upper = normcdf(upper, mu, sigma);
cdf_lower = normcdf(lower, mu, sigma);
p = cdf_upper - cdf_lower;
b = (1-p) ^ (n - 1);
results = zeros(sz, sz);
mask = rand(sz, sz) > b; % mask value 1 means case (a), 0 means case (b)
num_a = sum(mask(:));
cdf_vals = rand(num_a, 1) * p + cdf_lower;
results(mask) = norminv(cdf_vals, mu, sigma);
results(~mask) = normrnd(mu, sigma, sz^2 - num_a, 1);
If you want to simulate this directly for some reason (which is going to involve a lot of wasted effort, but apparently you don't like "the complications of statistics" -- by the way, this is probability, not statistics), you can generate the first matrix and then replace only the elements that don't fall in your desired range. For example:
mu = 0;
sigma = .2;
n = 10;
m = 10;
num_runs = 20;
lower = .2;
upper = .3;
result = normrnd(mu, sigma, n, m);
for i = 1 : (num_runs - 1)
to_replace = (result < lower) | (result > upper);
result(to_replace) = normrnd(mu, sigma, sum(to_replace(:)), 1);
end
To demonstrate that these are the same, here's a plots of the empirical CDFs of doing this for 1x1 matrices 100,000 times. (That is, I ran both functions 100k times and saved the results, then used cdfplot to plot values on the x axis vs portion of the obtained values that are less than that on the y axis.)
They're identical. (Indeed, a K-S test for identity of distribution gives a p-value of .71.) But the direct way was a bunch faster to run.