Generating a set of emissions given a transition matrix and starting state in a hidden markov model - simulation

I have the transition matrix, emission matrix and starting state for a hidden Markov model. I want to generate a sequence of observations (emissions). However, I'm stuck on one thing.
I understand how to choose among two states (or emissions). If Event A probability x, then Event B (or, really not-A) occurs with probability 1-x. To generate a sequence of A's and B's, with a random number, rand, you do the following.
for iteration in iterations:
observation[iteration] <- A if rand < x else B
I don't understand how to extend this to more than two variables. For example, if three events occur such that Event A occurs with probability x1, Event B with x2 and Event C with 1-(x1+x2), then how do I extend the above pseudocode?
I didn't find the answer Googling. In fact I get the impression that I'm missing a basic fact that many of the notes online assume. :-/

One way would be
x<-rand()
if x < x1 observation is A
else if x < x1 + x2 observation is B
else observation is C
Of course if you have a large number of alternatives it might be better to build a cumulative probability table (holding x1, x1+x2, x1+x2+x3 ...) and then do a binary search in that table given the random number. If you are willing to do more preprocessing, there is an even more efficient way, see here for example

The two value case is a binomial distribution, and you generate random draws from a binomial distribution (a series of coin flips, essentially).
For more than 2 variables, you need to draw samples from a multinomial distribution, which is simply a generalisation of the binomial distribution for n>2.
Regardless of what language you use, there should most likely be built-in functions to accomplish this task. Below is some code in Python, which simulates a set of observations and states given your hmm model object:
import numpy as np
def random_MN_draw(n, probs):
""" get X random draws from the multinomial distribution whose probability is given by 'probs' """
mn_draw = np.random.multinomial(n,probs) # do 1 multinomial experiment with the given probs with probs= [0.5,0.5], this is a coin-flip
return np.where(mn_draw == 1)[0][0] # get the index of the state drawn e.g. 0, 1, etc.
def simulate(self, nSteps):
""" given an HMM = (A, B1, B2 pi), simulate state and observation sequences """
lenB= len(self.emission)
observations = np.zeros((lenB, nSteps), dtype=np.int) # array of zeros
states = np.zeros(nSteps)
states[0] = self.random_MN_draw(1, self.priors) # appoint the first state from the prior dist
for i in range(0,lenB): # initialise observations[i,0] for all observerd variables
observations[i,0] = self.random_MN_draw(1, self.emission[i][states[0],:]) #ith variable array, states[0]th row
for t in range(1,nSteps): # loop through t
states[t] = self.random_MN_draw(1, self.transition[states[t-1],:]) # given prev state (t-1) pick what row of the A matrix to use
for i in range(0,lenB): # loop through the observed variable for each t
observations[i,t] = self.random_MN_draw(1, self.emission[i][states[t],:]) # given current state t, pick what row of the B matrix to use
return observations,states
In pretty much every language, you can find equivalents of
np.random.multinomial()
for multinomial and other discrete or continuous distributions as built-in functions.

Related

Qiskit QRAM encoding classical data into quantum state

I'm having trouble to encode classical data into quantum state in Qiskit IBM Quantum Lab. Let me explain the problem clearly: For university purpose I have to encode two 4-dimensional vectors with amplitude encoding (i.e using QRAM) and confront them with the fidelity distance. I wrote something like this:
#qram
def encodeVector(circuit,data,i,controls,rotationQubit,ancillaQubits):
#mcry(angolo,controls,target,ancilla)
# |00>
circuit.x(i)
circuit.mcry(np.arcsin(data[0]),controls,rotationQubit,ancillaQubits)
circuit.x(i)
circuit.barrier()
# |01>
circuit.x(i[1])
circuit.mcry(np.arcsin(data[1]),controls,rotationQubit,ancillaQubits)
circuit.x(i[1])
circuit.barrier()
# |10>
circuit.x(i[0])
circuit.mcry(np.arcsin(data[2]),controls,rotationQubit,ancillaQubits)
circuit.x(i[0])
circuit.barrier()
# |11>
circuit.mcry(np.arcsin(data[3]),controls,rotationQubit,ancillaQubits)
I know I need log(4)=2 qbits to encode 4 components of one vector. So the circuit is something like this: 2 qbit |i> for the first vector, 2 qbit |j> for the second one and finally 2 qbit |r> for the rotation. The teta angle can be found by applying arcsin to the components I think. And first of all I need to create registers 00,01,10,11 with an Hadamard Gate on qbit i and j (superposition). Let's post the code:
psi_norm = [1,0,0,0]
phi_norm = [0,0,0,1]
prova = QuantumRegister(1,"p") #for fidelity
i = QuantumRegister(2,"i") #first vector
j = QuantumRegister(2,"j") #second vector
r = QuantumRegister(2,"r") #rotation qbit
b = ClassicalRegister(1,"b") #for measurement
circuit = QuantumCircuit(prova,i,j,r,q,b)
circuit.h(i)
circuit.h(j)
circuit.barrier()
encodeVector(circuit, psi_norm, i, i[:], r[0],None) #encode first vector
circuit.barrier()
encodeVector(circuit, phi_norm, j, j[:], r[1],None) #encode second one
Now I calculate the fidelity distance which is the following circuit:
#fidelity
circuit.h(prova[0])
circuit.cswap(prova[0],i[0],j[0])
circuit.cswap(prova[0],i[1],j[1])
circuit.cswap(prova[0],r[0],r[1])
circuit.h(prova[0])
circuit.measure(prova[0],b[0])
The vector are orthogonal so the fidelity must have probabilities equal to 1/2, but in my case I get them wrong and I don't know where I make mistakes. Here the histogram:
https://i.stack.imgur.com/eqr47.png

MATLAB's pcacov on numpy/scipy?

I was wondering what function in numpy/scipy corresponded to pcacov() in MATLAB. If there isn't a corresponding one, what would be the best way to implement the function?
Thanks!
NumPy and SciPy don't have specific routines for PCA, but they do have the linear algebra primitives required to compute it. Any pca function in any language will basically be just a light wrapper around an eigenvalue or singular value decomposition, with different conventions regarding centering, normalization, meaning of matrix dimensions, and terms (eigenvectors, principal components, principal vectors, latent variables, etc. are all different names for the same thing, sometimes with slight variations).
So, for example, given a matrix X you can compute the PCA using the SVD:
import numpy as np
def pca(X):
X_centered = X - X.mean(0)
u, s, vt = np.linalg.svd(X_centered)
evals = s[::-1] ** 2 / (X.shape[0] - 1)
evecs = vt[::-1].T
return evals, evecs
np.random.seed(0)
X = np.random.rand(100, 3)
evals, evecs = pca(X)
print(evals)
# [ 0.06820946 0.08738236 0.09858988]
print(evecs)
# [[-0.49659797 0.4567562 -0.73808145]
# [ 0.34847559 0.88371847 0.31242029]
# [ 0.79495611 -0.10205609 -0.59802118]]
If you have a covariance matrix, you can compute the PCA using an eigenvalue decomposition:
def pcacov(C):
return np.linalg.eigh(C)
C = np.cov(X.T)
evals, evecs = pcacov(C)
print(evals)
# [ 0.06820946 0.08738236 0.09858988]
print(evecs)
# [[-0.49659797 -0.4567562 -0.73808145]
# [ 0.34847559 -0.88371847 0.31242029]
# [ 0.79495611 0.10205609 -0.59802118]]
The results are the same, up to a sign in the eigenvector columns.
Now, I've used a particular set of conventions here regarding whether datapoints are in rows or columns, how the covariance is normalized, etc. and those details vary from implementation to implementation of PCA. So the Matlab code might give different results because it's using different conventions internally. But under the hood, it's doing something very similar to the computations used above.

Change the random number generator in Matlab function

I have a task to complete that requires quasi-random numbers as input, but I notice that the Matlab function I want to use does not have an option to select any of the quasi generators I want to use (e.g. Halton, Sobol, etc.). Matlab has them as stand alone functions and not as options in the ubiquitous 'randn' and 'rng' functions. What MatLab uses is the Mersenne Twister, a pseudo generator. So for instance the copularnd uses 'randn'/'rng' which is based on pseudo random numbers....
Is there a way to incorporate them into the rand or rng functions embedded in other code (e.g.copularnd)? Any pointers would be much appreciated. Note; 'copularnd' calls 'mvnrnd' which in turn uses 'randn' and then pulls 'rng'...
First you need to initialize the haltonset using the leap, skip, and scramble properties.
You can check the documents but the easy description is as follows:
Scramble - is used for shuffling the points
Skip - helps to exclude a range of points from the set
Leap - is the size of jump from the current selected point to the next one. The points in between are ignored.
Now you can built a haltonset object:
p = haltonset(2,'Skip',1e2,'Leap',1e1);
p = scramble(p,'RR2');
This makes a 2D halton number set by skipping the first 100 numbers and leaping over 10 numbers. The scramble method is 'PR2' which is applied in the second line. You can see that many points are generated:
p =
Halton point set in 2 dimensions (818836295885536 points)
Properties:
Skip : 100
Leap : 10
ScrambleMethod : RR2
When you have your haltonset object, p, you can access the values by just selecting them:
x = p(1:10,:)
Notice:
So, you need to create the object first and then use the generated points. To get different results, you can play with Leap and Scramble properties of the function. Another thing you can do is to use a uniform distribution such as randi to select numbers each time from the generated points. That makes sure that you are accessing uniformly random parts of the dataset each time.
For instance, you can generate a random index vector (4 points in this example). And then use those to select points from the halton points.
>> idx = randi(size(p,1),1,4)
idx =
1.0e+14 *
3.1243 6.2683 6.5114 1.5302
>> p(idx,:)
ans =
0.5723 0.2129
0.8918 0.6338
0.9650 0.1549
0.8020 0.3532
link
'qrandstream' may be the answer I am looking for....with 'qrand' instead of 'rand'
e.g..from MatLab doc
p = haltonset(1,'Skip',1e3,'Leap',1e2);
p = scramble(p,'RR2');
q = qrandstream(p);
nTests = 1e5;
sampSize = 50;
PVALS = zeros(nTests,1);
for test = 1:nTests
X = qrand(q,sampSize);
[h,pval] = kstest(X,[X,X]);
PVALS(test) = pval;
end
I will post my solution once I am done :)

basic help using hmm to clasify a sequence

I am very new to matlab, hidden markov model and machine learning, and am trying to classify a given sequence of signals. Please let me know if the approach I have followed is correct:
create a N by N transition matrix and fill with random values which sum to 1for each row. (N will be the number of states)
create a N by M emission/observation matrix and fill with random values which sum to 1 for each row
convert different instances of the sequence (i.e each instance will be saying the word 'hello' ) into one long stream and feed each stream to the hmm train function such that:
new_transition_matrix old_transition_matrix = hmmtrain(sequence,old_transition_matrix,old_emission_matrix)
give the final transition and emission matrix to hmm decode with an unknown sequence to give the probability
i.e [posterior_states logrithmic_probability] = hmmdecode( sequence, final_transition_matrix,final_emission_matris)
1. and 2. are correct. You have to be careful that your initial transition and emission matrices are not completely uniform, they should be slightly randomized for the training to work.
3. I would just feed in the 'Hello' sequences separately rather than concatenating them to form a single long sequence.
Let's say this is the sequence for Hello: [1,0,1,1,0,0]. If you form one long sequence from 3 'Hello' sequences, you would get:
data = [1,0,1,1,0,0,1,0,1,1,0,0,1,0,1,1,0,0]
This is not ideal, instead you should feed the sequences in separately like:
data = [1,0,1,1,0,0; 1,0,1,1,0,0; 1,0,1,1,0,0].
Since you are using MatLab, I would recommend using the HMM toolbox by Murphy. It has a demo on how you can train an HMM with multiple observation sequences:
M = 3;
N = 2;
% "true" parameters
prior0 = normalise(rand(N ,1));
transmat0 = mk_stochastic(rand(N ,N ));
obsmat0 = mk_stochastic(rand(N ,M));
% training data: a 5*6 matrix, e.g. 5 different 'Hello' sequences of length 6
number_of_seq = 5;
seq_len= 6;
data = dhmm_sample(prior0, transmat0, obsmat0, number_of_seq, seq_len);
% initial guess of parameters
prior1 = normalise(rand(N ,1));
transmat1 = mk_stochastic(rand(N ,N ));
obsmat1 = mk_stochastic(rand(N ,M));
% improve guess of parameters using EM
[LL, prior2, transmat2, obsmat2] = dhmm_em(data, prior1, transmat1, obsmat1, 'max_iter', 5);
LL
4. What you say is correct, below is how you calculate the log probaility in the HMM toolbox:
% use model to compute log[P(Obs|model)]
loglik = dhmm_logprob(data, prior2, transmat2, obsmat2)
Finally: Have a look at this paper by Rabiner on how the mathematics work if anything is unclear.
Hope this helps.

Frequency array feeds FFT

The final goal I am trying to achieve is the generation of a ten minutes time series: to achieve this I have to perform an FFT operation, and it's the point I have been stumbling upon.
Generally the aimed time series will be assigned as the sum of two terms: a steady component U(t) and a fluctuating component u'(t). That is
u(t) = U(t) + u'(t);
So generally, my code follows this procedure:
1) Given data
time = 600 [s];
Nfft = 4096;
L = 340.2 [m];
U = 10 [m/s];
df = 1/600 = 0.00167 Hz;
fn = Nfft/(2*time) = 3.4133 Hz;
This means that my frequency array should be laid out as follows:
f = (-fn+df):df:fn;
But, instead of using the whole f array, I am only making use of the positive half:
fpos = df:fn = 0.00167:3.4133 Hz;
2) Spectrum Definition
I define a certain spectrum shape, applying the following relationship
Su = (6*L*U)./((1 + 6.*fpos.*(L/U)).^(5/3));
3) Random phase generation
I, then, have to generate a set of complex samples with a determined distribution: in my case, the random phase will approach a standard Gaussian distribution (mu = 0, sigma = 1).
In MATLAB I call
nn = complex(normrnd(0,1,Nfft/2),normrnd(0,1,Nfft/2));
4) Apply random phase
To apply the random phase, I just do this
Hu = Su*nn;
At this point start my pains!
So far, I only generated Nfft/2 = 2048 complex samples accounting for the fpos content. Therefore, the content accounting for the negative half of f is still missing. To overcome this issue, I was thinking to merge the real and imaginary part of Hu, in order to get a signal Huu with Nfft = 4096 samples and with all real values.
But, by using this merging process, the 0-th frequency order would not be represented, since the imaginary part of Hu is defined for fpos.
Thus, how to account for the 0-th order by keeping a procedure as the one I have been proposing so far?