Jacobian Multiply Function with Linear Least Squares
Using a Jacobian multiply function, you can solve a least-squares problem of the form
such thatlb ≤ x ≤ ub
, for problems whereCis very large, perhaps too large to be stored. For this technique, use the'trust-region-reflective'
algorithm.
For example, consider a problem whereCis a 2n-by-n matrix based on a circulant matrix. The rows ofCare shifts of a row vectorv. This example has the row vectorvwith elements of the form :
,
where the elements are cyclically shifted.
This least-squares example considers the problem where
,
and the constraints are for .
For large enough , the dense matrixCdoes not fit into computer memory ( is too large on one tested system).
A Jacobian multiply function has the following syntax.
w = jmfcn(Jinfo,Y,flag)
Jinfo
is a matrix the same size asC, used as a preconditioner. IfCis too large to fit into memory,Jinfo
should be sparse.Y
is a vector or matrix sized so thatC*Y
orC'*Y
works as matrix multiplication.flag
tellsjmfcn
which product to form:
flag
> 0 ⇒w = C*Y
flag
< 0 ⇒w = C'*Y
flag
= 0 ⇒w = C'*C*Y
BecauseCis such a simply structured matrix, you can easily write a Jacobian multiply function in terms of the vectorv, without formingC. Each row ofC*Y
is the product of a circularly shifted version ofvtimesY
. Usecircshift
to circularly shiftv.
To computeC*Y
, computev*Y
to find the first row, then shiftvand compute the second row, and so on.
To computeC'*Y
, perform the same computation, but use a shifted version oftemp
, the vector formed from the first row ofC'
:
temp = [fliplr(v),fliplr(v)];
temp = [circshift(temp,1,2),circshift(temp,1,2)]; % Now temp = C'(1,:)
To computeC'*C*Y
, simply computeC*Y
using shifts ofv, and then computeC'
times the result using shifts offliplr(v)
.
The helper functionlsqcirculant3
is a Jacobian multiply function that implements this procedure; it appears at theend of this example.
ThedolsqJac3
helper function at theend of this example建立了向量vand calls the solverlsqlin
using thelsqcirculant3
Jacobian multiply function.
Whenn
= 3000,Cis an 18,000,000-element dense matrix. Determine the results of thedolsqJac3
function forn
= 3000 at selected values ofx, and display the output structure.
[x,resnorm,residual,exitflag,output] = dolsqJac3(3000);
Local minimum possible. lsqlin stopped because the relative change in function value is less than the function tolerance.
disp(x(1))
5.0000
disp (x (1500))
-0.5201
disp(x(3000))
-5.0000
disp(output)
iterations: 16 algorithm: 'trust-region-reflective' firstorderopt: 5.9351e-05 cgiterations: 36 constrviolation: [] linearsolver: [] message: 'Local minimum possible.↵↵lsqlin stopped because the relative change in function value is less than the function tolerance.'
Helper Functions
这段代码创建了lsqcirculant3
helper function.
functionw = lsqcirculant3(Jinfo,Y,flag,v)% This function computes the Jacobian multiply function% for a 2n-by-n circulant matrix example.ifflag > 0 w = Jpositive(Y);elseif国旗< 0 w = Jnegative (Y);elsew = Jnegative(Jpositive(Y));endfunctiona = Jpositive(q)% Calculate C*qtemp = v; a = zeros(size(q));% Allocating the matrix aa = [a;a];% The result is twice as tall as the input.forr = 1:size(a,1) a(r,:) = temp*q;% Compute the rth rowtemp = circshift(temp,1,2);% Shift the circulantendendfunctiona = Jnegative(q)% Calculate C'*qtemp = fliplr(v); temp = circshift(temp,1,2);% Shift the circulant for C'len = size(q,1)/2;% The returned vector is half as long% as the input vector.a = zeros(len,size(q,2));% Allocating the matrix aforr = 1:len a(r,:) = [temp,temp]*q;% Compute the rth rowtemp = circshift(temp,1,2);% Shift the circulantendendend
这段代码创建了dolsqJac3
helper function.
function[x,resnorm,residual,exitflag,output] = dolsqJac3(n)%r = 1:n-1;% Index for making vectorsv(n) = (-1)^(n+1)/n;% Allocating the vector vv(r) =( -1).^(r+1)./r;%现在应该2 n - Cby-n circulant matrix based on v,% but it might be too large to fit into memory.r = 1:2*n; d(r) = n-r; Jinfo = [speye(n);speye(n)];% Sparse matrix for preconditioning% This matrix is a required input for the solver;% preconditioning is not used in this example.% Pass the vector v so that it does not need to be% computed in the Jacobian multiply function.options = optimoptions('lsqlin','Algorithm','trust-region-reflective',...'JacobianMultiplyFcn',@(Jinfo,Y,flag)lsqcirculant3(Jinfo,Y,flag,v)); lb = -5*ones(1,n); ub = 5*ones(1,n); [x,resnorm,residual,exitflag,output] =...lsqlin(Jinfo,d,[],[],[],[],lb,ub,[],options);end