function [] = compute_all_RP_estimates(X, m1, m2, m1m2, ffname)
	% This function computes the estimates 
	% of the inner product between two 
	% vectors via random projections. 
	% For V_{2,k}=XR, the estimates are 
	% computed for k = 1,2,..,100.

	% We look at how estimates vary across 
	% Newton Raphson for MLE, Secant Method 
	% for MLE, and the fixed point iteration
	% given by the CVE. 

	% Inputs:
	% 'X': A matrix of size 2 by p (set to 10000
	% in experiments)
	% 'm1': A scalar value corresponding to 
	% the squared norm of the first vector 
	% (equivalent to sigma_{11})
	% 'm2': A scalar value corresponding to 
	% the squared norm of the second vector 
	% (equivalent to sigma_{22})
	% 'm1m2': A scalar value corresponding 
	% to the product of m1*m2
	% 'ffname': A string specifying the 
	% filename where the results are saved.

	MaxIterations = 10000;

	% Arrays to store estimates
	% Original RP estimate
	est_mat_orig = zeros(MaxIterations,100);

	% NR estimate for MLE, for one iteration, and 
	% for 10 iterations/update steps till convergence
	% For 10 iterations/update steps, also 
	% record number of iterations and update value
	% till convergence
	est_mat_NR = zeros(MaxIterations,100);
	NR_iter_mat = zeros(MaxIterations,100);
	NR_values_mat = zeros(MaxIterations,11,100);

	% Secant estimate for MLE for 10 iterations
	% and recording of number of iterations/update 
	% steps till actual convergence
	% and also 
	est_mat_sec = zeros(MaxIterations,100);
	sec_iter_mat = zeros(MaxIterations, 100);
	sec_values_mat = zeros(MaxIterations,12,100);

	% CVE for empirical covariances and variances
	% CVE for EM for 10 iterations
	% and recording of number of 
	% iterations/update steps till actual 
	% convergence

	est_mat_CV = zeros(MaxIterations,100);
	est_mat_empirical_CV = zeros(MaxIterations,100);
	CV_iter_mat = zeros(MaxIterations,100);
	CV_values_mat = zeros(MaxIterations,11,100);

	% Recording number of real roots for polynomial
	% and their values
	real_roots_mat = zeros(MaxIterations,100);
	cubic_roots_mat = zeros(MaxIterations,100);

	% actual inner product for x1 x2
	true_IP = sum(X(1,:).*X(2,:)); 

	for num_iter = 1:MaxIterations
		if(mod(num_iter, 100) == 0)
			[num2str(num_iter), ' for ', ffname]
		end

		% Compute V = XR
		V = X*normrnd(0,1,size(X,2), 100);
    
    % Corresponds to y1 (first sufficient statistic)
    % for values of k for 1:100    
		v1sq = cumsum(V(1,:).^2)./(1:100);

    % Corresponds to y2 (first sufficient statistic)
    % for values of k for 1:100 
		v2sq = cumsum(V(2,:).^2)./(1:100);
    
    % Corresponds to y3 (first sufficient statistic)
    % for values of k for 1:100 
    v1v2  = cumsum(V(1,:).*V(2,:))./(1:100);

    % Stores estimated value of inner product
    est_mat_orig(num_iter,:) = v1v2;
    

		[est_mat_NR(num_iter,:), NR_iter_mat(num_iter,:), NR_values_mat(num_iter,:,:)] = newton_raphson_cubic_vectorized(v1sq, v2sq, v1v2, m1, m2, m1m2, 10);

		[est_mat_sec(num_iter,:), sec_iter_mat(num_iter,:), sec_values_mat(num_iter,:,:)] = secant_cubic_vectorized(v1sq, v2sq, v1v2, m1, m2, m1m2);      
        
		cvrv1fact = (v1sq - m1)*m2;
		cvrv2fact = (v2sq - m2)*m1;
        
		cvfact = cvrv1fact + cvrv2fact;
		[est_mat_CV(num_iter,:), CV_iter_mat(num_iter,:),CV_values_mat(num_iter,:,:)] = cv_vectorized(v1v2, cvfact, m1m2);

    % CV with empirical values (require covariances)
    % Var[X] = E[X^2] - (E[X])^2 ; 
    % empirical var divides by n-1

    empvarv1sq = cumsum(V(1,:).^4)./[1 1:99] - v1sq.^2;
    empvarv2sq = cumsum(V(2,:).^4)./[1 1:99] - v2sq.^2;
    empvarv1v2 = cumsum((V(1,:).*V(2,:)).^2)./[1 1:99] - v1v2.^2;
    empcovv1sqv2sq = cumsum((V(1,:).^2).* (V(2,:).^2))./[1 1:99] - v1sq.*v2sq;
    empcovv1sqv1v2 = cumsum((V(1,:).^2).* (V(1,:).*V(2,:)))./[1 1:99] - v1sq.*v1v2;
    empcovv2sqv1v2 = cumsum((V(2,:).^2).* (V(1,:).*V(2,:)))./[1 1:99] - v2sq.*v1v2;

    c1emp = (empcovv1sqv2sq.*empcovv2sqv1v2 -empvarv2sq.*empcovv1sqv1v2)./(empvarv1sq.*empvarv2sq - empcovv1sqv2sq.^2);
    c2emp = (empcovv1sqv2sq.*empcovv1sqv1v2 -empvarv1sq.*empcovv2sqv1v2)./(empvarv1sq.*empvarv2sq - empcovv1sqv2sq.^2);

    est_mat_empirical_CV(num_iter,:) = v1v2 + c1emp.*(v1sq - m1) + c2emp.*(v2sq-m2);

		b = -v1v2;
		c = m1*v2sq + m2*v1sq - m1m2;
		d = -m1m2*v1v2;
		Dvec = 18.*b.*c.*d - 4*(b.^3).*d + (b.^2) .* c.^2 - 4*c.^3 -27*d.^2;
		Dvec(Dvec>= 0) = 1; % 3 real root
		Dvec(Dvec< 0) = 0; % 1 real root
		cubic_roots_mat(num_iter,:) = Dvec;	
		for s = 1:100
			troots = roots([1 b(s) c(s) d(s)]);
			troots = troots(imag(troots) == 0);
			% Might have 3 real roots, but if so
			% we will exclude this
			real_roots_mat(num_iter,s) = troots(1);
		end
	end


	save(ffname,'est_mat_orig', 'est_mat_NR', 'NR_iter_mat', 'NR_values_mat','est_mat_sec', 'sec_iter_mat', 'sec_values_mat', 'est_mat_CV', 'est_mat_empirical_CV', 'CV_iter_mat', 'CV_values_mat', 'true_IP','cubic_roots_mat', 'real_roots_mat');

end


