First, thank you for all of the work that you've devoted to this project. It's an incredible resource!
I am working on the following problem and I would really appreciate some guidance.
I have the following:
- Tx1 vector 'Z'
- TxM matrix 'Y'
- NxT matrix 'X'
I am trying to find the MxN matrix 'A' of rank 'k' that minimizes the following function:
function f = log_optimal(A)
f = 0;
for t=1:T,
f = f - log( Z(t) + Y(t,:)*A*X(:,t) );
end
f = f/T;
end
I'm comfortable computing the Euclidean gradient, but if it's not too much trouble, I could use a quick refresher on the Euclidean Hessian.
Also, I would really appreciate some advice on which of the fixed-rank factory manifolds in the toolbox is best suited to my purpose. I've been trying to work from the example for fixedrank_2factors (http://www.manopt.org/manifold_documentation_fixedrank_2factors.html), but I'm only beginning to learn about manifolds and at this point I don't understand them well enough to know whether this is the best fit for my problem.
Finally, I was wondering if you could provide a list of the necessary Matlab toolboxes that are required to run your toolbox. For example, I discovered today that I need to have the Control toolbox installed to have access to the 'lyap' function. Do you know if there are any other required toolboxes?
Thanks again for sharing all of your hard work!
Jeremy Graveline
function X = my_lyap(A, B, C)% Replacement for lyap if it is not available.% A, B and C must be square and have the same size.% This is excruciatingly slower than it could be.mat = @(x) reshape(x, size(A));vec = @(X) X(:);% % This exploits the structure better, but doesn't work very well and% % is actually slow.% tol = 1e-8; maxit = 1000;% [x, ~] = gmres(@(x) vec(A*mat(x) + mat(x)*B), -vec(C), size(A, 1), tol, maxit);% This will break down for sizes larger than, say, 30, but is otherwise% pretty accurate (it's just slow though).I = eye(size(A));x = -(kron(I, A) + kron(B', I))\vec(C);X = mat(x);end
function manopt_jeremy_graveline()% Arbitrary sizesm = 10;n = 12;t = 6;k = 3;% Random dataz = 1+rand(t, 1);X = randn(n, t);Y = randn(t, m);problem.M = fixedrankfactory_2factors(m, n, k);problem.cost = @cost;function f = cost(A)% A is a structure representing a rank-k matrix L*R'L = A.L;R = A.R;f = -mean(log(z + diag((Y*L)*(R'*X))));endproblem.egrad = @egrad;function g = egrad(A)L = A.L;R = A.R;% We differentiate with respect to L and R separatelyw = z + diag((Y*L)*(R'*X));RtX = R'*X;YL = Y*L;g = problem.M.zerovec(A);for i = 1 : tg.L = g.L - (Y(i, :)'*RtX(:, i)')/w(i);g.R = g.R - (X(:, i)*YL(i, :))/w(i);endg.L = g.L / t;g.R = g.R / t;endcheckgradient(problem); pause;options.tolgradnorm = 1e-12;A = conjugategradient(problem, [], options);end
Thanks very much for your reply.
I experimented a bit more, and the problem seems to be that the argument to 'log' can go negative during the optimization, so that the cost function can return an imaginary value. I added some code to essentially truncate the argument to log in the cost function and ensure that it remains strictly positive. With that correction, the algorithm seems to converge (at least for most random data that I generate). I've pasted some code below (sorry, but I couldn't figure out how to give the code a different font to make it stand out).
I have some questions that I'd really appreciate your input on:
1) As I mentioned, I'm just learning about manifolds, and I don't have a good sense of the role that different geometries play. Is there a particular geometry that's best suited to the problem I'm trying to solve, or should I just experiment?
2) Is there a more practical/elegant method to keep the cost function real (i.e., the argument to log strictly positive).
3) Can you help me to understand the specific first order conditions that the optimization routine tries to set to 0?
Here's the code:
function test_manopt()
%% example to test manopt capabilities
t = 1000; m = 15; n = 8; k = 2;
X = [ones(1,t);randn(n-1,t)];
dt = 1/52; sig = 0.25; r = 0.03;
%% matrix of coefficients on "predicter"
A.R = randn(n,k); A.L = randn(m,k);
A.L = 0.05*A.L./repmat(mean(((A.L*A.R')*X)')',1,k);
%% mxt vector of excess returns
Y = exp( (r + (A.L*A.R')*X + 0.5*sig^2).*dt + sqrt(dt).*sig*randn(m,t));
r = exp(repmat(r.*dt,1,t));
Y = Y - ones(m,1)*r;
%% Finished generating random data
%% Create the problem structure
problem.M = fixedrankfactory_2factors(m,n,k);
%% Define the problem cost function
problem.cost = @cost;
function f = cost(Mat)
w = r + dot(Mat.L'*Y,Mat.R'*X);
%% make sure argument to log is strictly positive
if all(w>0)
f = -mean(log(w));
else
f = 10;
end
end
%% Define gradient of cost function
problem.grad = @(Mat) problem.M.egrad2rgrad(Mat, egrad(Mat));
function g = egrad(Mat)
LY = Mat.L'*Y;
RX = Mat.R'*X;
w = r + dot(LY,RX);
g = problem.M.zerovec(Mat);
for i=1:t
g.L = g.L - (Y(:,i)*RX(:,i)')/w(i);
g.R = g.R - (X(:,i)*LY(:,i)')/w(i);
end
g.L = g.L / t;
g.R = g.R / t;
end
checkgradient(problem); pause;
options.tolgradnorm = 1e-12; options.maxiter = 5000;
%% reasonable starting guess for problem
guessA = A; guessA.L = guessA.L./sig;
[solA1, cost1, info1] = conjugategradient(problem, guessA, options);
end
Thanks again for your help and all of your work on this toolbox.
The cost function is bounded for specific problem I'm working on (Y can be negative). However, not every random data set I generate has a bounded solution. For the ones that do, the toolbox is working great with my rough hack!
Also, thanks for your advice on keeping the cost function smooth. -log(x) -> \infty as x->0, but my understanding is that I need to adjust the cost function to keep it smooth but make it increase more quickly as x->0 so that the algorithm doesn't jump to an x<0. Is that correct?
Can I steal some advice on which built-in fixed-rank manifold I should start with?
Thanks again!
Jeremy
One more thing that I forgot to mention. I'm trying to use checkhessian to test whether I've coded in the Hessian for my problem correctly. I get the message "The slope should be 3. It appears to be: 2."
However, I get the same message when I run the example function, fixedrank_test(), at http://www.manopt.org/manifold_documentation_fixedrank_2factors.html
Perhaps there is a bug somewhere?
Best,
Jeremy