% Calculation of gradient and objective for least-squares MMMF.
%
% function [obj,grad,lossobj,regobj] = m3fls(v,Y,lambda,varargin)
% v - vector of parameters [n*p+m*p,1]
% Y - target matrix [n,m]
% lambda - regularization parameter [scalar]
% obj - value of objective at v [scalar]
% grad - gradient at v [n*p+m*p,1]
% lossobj - loss component of objective [scalar]
% regobj - regularization component of objective [scalar]
% 
% Written by Jason Rennie, February 2006
% Last modified: Wed Mar 15 11:36:26 2006

function [obj,grad,lossobj,regobj] = m3fls(v,Y,lambda,varargin)
  fn = mfilename;
  if nargin < 3
    error('insufficient parameters')
  end
  % Parameters that can be set via varargin
  verbose = 1;
  % Process varargin
  paramgt;
  
  t0 = clock;
  [n,m] = size(Y);
  p = length(v)./(n+m);
  if p ~= floor(p) | p < 1
    error('dimensions of v and Y don''t match');
  end
  U = reshape(v(1:n*p),n,p);
  V = reshape(v(n*p+1:n*p+m*p),m,p);

  X = U*V';
  XminusY = X-Y;
  dU = 2.*XminusY*V + lambda.*U; % [n,p]
  dV = 2.*XminusY'*U + lambda.*V; % [m,p]
  regobj = lambda.*(sum(U(:).^2)+sum(V(:).^2))./2; % [scalar]
  lossobj = sum(XminusY(:).^2);
  obj = regobj + lossobj;
  grad = [dU(:); dV(:)];
  if verbose
    fprintf(1,'lambda=%.2e obj=%.2e grad''*grad=%.2e time=%.1f\n',lambda,obj,grad'*grad,etime(clock,t0));
  end
