function [a_now, iter_mat, values_mat] = secant_cubic_vectorized(v1sq, v2sq, v1v2, m1, m2, m1m2)

  % This function implements a vectorized 
  % version of the secant method
  % 
  % Inputs:
  % 'v1sq' 'v2sq': Vectors of respective 
  % squared values
  % 'v1v2': Vector of inner products 
  % 'm1', 'm2': Scalars ; corresponds to 
  % sigma_{11}, sigma_{22}
  % 'm1m2': Scalars; corresponds to 
  % sigma_{11}*sigma_{22}
  % 'numNRIter': Iterations for NR to run

  % Outputs:
  % 'a_now': The approximation of the 
  % root after the iterations.
  % 'iter_mat': A vector storing the 
  % number of iterations it took to reach
  % the approximation within the desired tolerance.

  TOL = 0.0001;
  tot_size = length(v1sq);
  a_now = v1v2;
  prev_prob = a_now;
  len_anow = tot_size;
  values_mat = nan(12,100);
  

  iter_mat = zeros(1, len_anow);

  a_prev = zeros(1, len_anow);

  % Terminate also when no more elements to do secant over 
  is_term = tot_size;
  
  % Check number of idxes to go ; we stop iterating an element when TOL is met
  idx_to_go = 1:len_anow;
  
  iter = 0;

  xprevprev = ones(1, len_anow) * -sqrt(m1m2);
  values_mat(1,:) = xprevprev;
  xprev = ones(1, len_anow) * sqrt(m1m2);
  values_mat(2,:) = xprev;
  while is_term > 0 && iter < 10

    iter_mat(idx_to_go) = iter_mat(idx_to_go) + 1;
    iter = iter + 1;
    
    % Update steps

    a2coef = -v1v2;
    a1coef = -m1m2 + v2sq*m1 + v1sq*m2;
    a0coef = -v1v2*m1m2;

    fxprevprev = xprevprev(idx_to_go).^3 + a2coef(idx_to_go).*xprevprev(idx_to_go).^2 + xprevprev(idx_to_go).*a1coef(idx_to_go) + a0coef(idx_to_go);
    fxprev = xprev(idx_to_go).^3 + a2coef(idx_to_go).*xprev(idx_to_go).^2 + a1coef(idx_to_go).*xprev(idx_to_go) + a0coef(idx_to_go);
    a_now(idx_to_go) = xprev(idx_to_go) - fxprev.*(xprev(idx_to_go) - xprevprev(idx_to_go))./(fxprev - fxprevprev);
    
    values_mat(iter+2,idx_to_go) = a_now(idx_to_go);
    % check which points to still iterate on    
    idx_to_go = idx_to_go(abs(a_now(idx_to_go) - xprev(idx_to_go)) > TOL);
    is_term = length(idx_to_go);
    % Update the indexes where we need to continue doing secant
    xprevprev(idx_to_go) = xprev(idx_to_go);
    xprev(idx_to_go) = a_now(idx_to_go);
  end

  % In case there is no convergence, we 
  % set this to the initial estimate 
  a_now(idx_to_go) = prev_prob(idx_to_go);
  
  % If there is convergence past the inner 
  % product bounds (via cosine rule), then 
  % set the MLE estimate to be the
  % upper (or corresponding) lower bound
  a_now(a_now > sqrt(m1m2)) = sqrt(m1m2);
  a_now(a_now < -sqrt(m1m2)) = -sqrt(m1m2);
end
