278 lines
12 KiB
Mathematica
278 lines
12 KiB
Mathematica
|
|
function varargout = norm(varargin)
|
||
|
|
%NORM (overloaded)
|
||
|
|
%
|
||
|
|
% t = NORM(x,P)
|
||
|
|
%
|
||
|
|
% The variable t can only be used in convexity preserving
|
||
|
|
% operations such as t<=1, max(t,y)<=1, minimize t etc.
|
||
|
|
%
|
||
|
|
% For matrices...
|
||
|
|
% NORM(X) models the largest singular value of X, max(svd(X)).
|
||
|
|
% NORM(X,2) is the same as NORM(X).
|
||
|
|
% NORM(X,1) models the 1-norm of X, the largest column sum, max(sum(abs(X))).
|
||
|
|
% NORM(X,inf) models the infinity norm of X, the largest row sum, max(sum(abs(X'))).
|
||
|
|
% NORM(X,'inf') same as above
|
||
|
|
% NORM(X,'fro') models the Frobenius norm, sqrt(sum(diag(X'*X))).
|
||
|
|
% NORM(X,'nuc') models the Nuclear norm, sum of singular values.
|
||
|
|
% NORM(X,'*') same as above
|
||
|
|
% NORM(X,'tv') models the (isotropic) total variation semi-norm
|
||
|
|
% For vectors...
|
||
|
|
% NORM(V) = norm(V,2) = standard Euclidean norm.
|
||
|
|
% NORM(V,inf) = max(abs(V)).
|
||
|
|
% NORM(V,1) = sum(abs(V))
|
||
|
|
%
|
||
|
|
% SEE ALSO SUMK, SUMABSK
|
||
|
|
|
||
|
|
%% ***************************************************
|
||
|
|
% This file defines a nonlinear operator for YALMIP
|
||
|
|
%
|
||
|
|
% It can take three different inputs
|
||
|
|
% For DOUBLE inputs, it returns standard double values
|
||
|
|
% For SDPVAR inputs, it generates an internal variable
|
||
|
|
%
|
||
|
|
% When first input is 'model' it returns the graph
|
||
|
|
% in the first output and structure describing some
|
||
|
|
% properties of the operator.
|
||
|
|
|
||
|
|
%% ***************************************************
|
||
|
|
switch class(varargin{1})
|
||
|
|
|
||
|
|
case 'sdpvar' % Overloaded operator for SDPVAR objects. Pass on args and save them.
|
||
|
|
if nargin == 1
|
||
|
|
varargout{1} = yalmip('define',mfilename,varargin{1},2);
|
||
|
|
else
|
||
|
|
switch varargin{2}
|
||
|
|
case {1,2,inf,'inf','fro'}
|
||
|
|
varargout{1} = yalmip('define',mfilename,varargin{:});
|
||
|
|
case 'tv'
|
||
|
|
if ~isreal(varargin{1})
|
||
|
|
error('Total variation norm not yet implemented for complex arguments');
|
||
|
|
end
|
||
|
|
if min(varargin{1}.dim)==1
|
||
|
|
varargout{1} = norm(diff(varargin{1}),1);
|
||
|
|
return
|
||
|
|
end
|
||
|
|
varargout{1} = yalmip('define','norm_tv',varargin{:});
|
||
|
|
case {'nuclear','*'}
|
||
|
|
if min(size(varargin{1}))==1
|
||
|
|
varargout{1} = norm(varargin{1},1);
|
||
|
|
else
|
||
|
|
varargout{1} = yalmip('define','norm_nuclear',varargin{:});
|
||
|
|
end
|
||
|
|
otherwise
|
||
|
|
if isreal(varargin{1}) & min(size(varargin{1}))==1 & isnumeric(varargin{2})
|
||
|
|
varargout{1} = pnorm(varargin{:});
|
||
|
|
else
|
||
|
|
error('norm(x,P) only supported for P = 1, 2, inf, ''fro'' and ''nuclear''');
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
case 'char' % YALMIP sends 'model' when it wants the epigraph or hypograph
|
||
|
|
switch varargin{1}
|
||
|
|
case 'graph'
|
||
|
|
t = varargin{2};
|
||
|
|
X = varargin{3};
|
||
|
|
p = varargin{4};
|
||
|
|
|
||
|
|
% Code below complicated by two things
|
||
|
|
% 1: Absolute value for complex data -> cone constraints on
|
||
|
|
% elements
|
||
|
|
% 2: SUBSREF does not call SDPVAR subsref -> use extsubsref.m
|
||
|
|
|
||
|
|
switch p
|
||
|
|
case 1
|
||
|
|
if issymmetric(X)
|
||
|
|
Z = sdpvar(size(X,1),size(X,2));
|
||
|
|
else
|
||
|
|
Z = sdpvar(size(X,1),size(X,2),'full');
|
||
|
|
end
|
||
|
|
if min(size(X))>1
|
||
|
|
if isreal(X)
|
||
|
|
z = reshape(Z,[],1);
|
||
|
|
x = reshape(X,[],1);
|
||
|
|
F = (-z <= x <= z);
|
||
|
|
else
|
||
|
|
F = ([]);
|
||
|
|
zvec = reshape(Z,1,[]);
|
||
|
|
xrevec=reshape(real(X),1,[]);
|
||
|
|
ximvec=reshape(imag(X),1,[]);
|
||
|
|
F = [F,cone([zvec;xrevec;ximvec])];
|
||
|
|
end
|
||
|
|
F = F + (sum(Z,1) <= t);
|
||
|
|
else
|
||
|
|
if isreal(X)
|
||
|
|
% Standard definition
|
||
|
|
% F = (-t <= X <= t);
|
||
|
|
X = reshape(X,[],1);
|
||
|
|
Z = reshape(Z,[],1);
|
||
|
|
Xbase = getbase(X);
|
||
|
|
Constant = find(~any(Xbase(:,2:end),2));
|
||
|
|
if ~isempty(Constant)
|
||
|
|
% Exploit elements without any
|
||
|
|
% decision variables
|
||
|
|
r1 = ones(length(Z),1);
|
||
|
|
r2 = zeros(length(Z),1);
|
||
|
|
r1(Constant) = 0;
|
||
|
|
r2(Constant) = abs(Xbase(Constant,1));
|
||
|
|
Z = Z.*r1 + r2;
|
||
|
|
end
|
||
|
|
F = (-Z <= X <= Z) + (sum(Z) <= t);
|
||
|
|
else
|
||
|
|
F = (cone([reshape(Z,1,[]);real(reshape(X,1,[]));imag(reshape(X,1,[]))]));
|
||
|
|
F = F + (sum(Z) <= t);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
case 2
|
||
|
|
if min(size(X))>1
|
||
|
|
F = ([t*eye(size(X,1)) X;X' t*eye(size(X,2))])>=0;
|
||
|
|
else
|
||
|
|
F = cone(X(:),t);
|
||
|
|
end
|
||
|
|
case {inf,'inf'}
|
||
|
|
if min(size(X))>1
|
||
|
|
Z = sdpvar(size(X,1),size(X,2),'full');
|
||
|
|
if isreal(X)
|
||
|
|
F = (-Z <= X <= Z);
|
||
|
|
else
|
||
|
|
F = ([]);
|
||
|
|
for i = 1:size(X,1)
|
||
|
|
for j = 1:size(X,2)
|
||
|
|
xi = extsubsref(X,i,j);
|
||
|
|
zi = extsubsref(Z,i,j);
|
||
|
|
F = F + (cone([real(xi);imag(xi)],zi));
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
F = F + (sum(Z,2) <= t);
|
||
|
|
else
|
||
|
|
if isreal(X)
|
||
|
|
F = (-t <= X <= t);
|
||
|
|
[M,m,infbound] = derivebounds(X);
|
||
|
|
if ~infbound
|
||
|
|
F = F + (0 <= t <= max(max(abs([m M]))));
|
||
|
|
end
|
||
|
|
else
|
||
|
|
F = ([]);
|
||
|
|
for i = 1:length(X)
|
||
|
|
xi = extsubsref(X,i);
|
||
|
|
F = F + (cone([real(xi);imag(xi)],t));
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
case 'fro'
|
||
|
|
X.dim(1)=X.dim(1)*X.dim(2);
|
||
|
|
X.dim(2)=1;
|
||
|
|
F = (cone(X,t));
|
||
|
|
case 'nuclear'
|
||
|
|
U = sdpvar(X.dim(2));
|
||
|
|
V = sdpvar(X.dim(1));
|
||
|
|
F = [trace(U)+trace(V) <= 2*t, [U X';X V]>=0];
|
||
|
|
case 'tv'
|
||
|
|
Dx = [diff(X,1,1);zeros(1,X.dim(2))];
|
||
|
|
Dy = [diff(X,1,2) zeros(X.dim(1),1)];
|
||
|
|
T = sdpvar(X.dim(1),X.dim(2),'full');
|
||
|
|
F = cone([reshape(T,1,[]);reshape(Dx,1,[]);reshape(Dy,1,[])]);
|
||
|
|
F = [F, sum(sum(T)) <= t];
|
||
|
|
otherwise
|
||
|
|
end
|
||
|
|
varargout{1} = F;
|
||
|
|
varargout{2} = struct('convexity','convex','monotonicity','none','definiteness','positive','model','graph');
|
||
|
|
varargout{3} = X;
|
||
|
|
|
||
|
|
case 'exact'
|
||
|
|
|
||
|
|
t = varargin{2};
|
||
|
|
X = varargin{3};
|
||
|
|
p = varargin{4};
|
||
|
|
if ~isreal(X) | isequal(p,2) | isequal(p,'fro') | min(size(X))>1 % Complex valued data, matrices and 2-norm not supported
|
||
|
|
varargout{1} = [];
|
||
|
|
varargout{2} = [];
|
||
|
|
varargout{3} = [];
|
||
|
|
else
|
||
|
|
if p==1
|
||
|
|
X = reshape(X,length(X),1);
|
||
|
|
absX = sdpvar(length(X),1);
|
||
|
|
d = binvar(length(X),1);
|
||
|
|
[M,m] = derivebounds(X);
|
||
|
|
|
||
|
|
if all(abs(sign(m)-sign(M))<=1)
|
||
|
|
|
||
|
|
% Silly convex case. Some coding to care of the
|
||
|
|
% case sign(0)=0...
|
||
|
|
d = ones(length(X),1);
|
||
|
|
d(m<0)=-1;
|
||
|
|
F = (t - sum(absX) == 0) + (absX == d.*X);
|
||
|
|
else
|
||
|
|
|
||
|
|
F = ([]);
|
||
|
|
|
||
|
|
|
||
|
|
% Some fixes to remove trivial constraints
|
||
|
|
% which caused problems in a user m
|
||
|
|
positive = find(m >= 0);
|
||
|
|
negative = find(M <= 0);
|
||
|
|
fixed = find(m==M);
|
||
|
|
if ~isempty(fixed)
|
||
|
|
positive = setdiff(positive,fixed);
|
||
|
|
negative = setdiff(negative,fixed);
|
||
|
|
end
|
||
|
|
if ~isempty(positive)
|
||
|
|
d = subsasgn(d,struct('type','()','subs',{{positive}}),1);
|
||
|
|
end
|
||
|
|
if ~isempty(negative)
|
||
|
|
d = subsasgn(d,struct('type','()','subs',{{negative}}),0);
|
||
|
|
end
|
||
|
|
if ~isempty(fixed)
|
||
|
|
notfixed = setdiff(1:length(m),fixed);
|
||
|
|
addsum = sum(abs(m(fixed)));
|
||
|
|
m = m(notfixed);
|
||
|
|
M = M(notfixed);
|
||
|
|
X = extsubsref(X,notfixed);
|
||
|
|
absX = extsubsref(absX,notfixed);
|
||
|
|
d = extsubsref(d,notfixed);
|
||
|
|
else
|
||
|
|
addsum = 0;
|
||
|
|
end
|
||
|
|
|
||
|
|
maxABSX = max([abs(m) abs(M)],[],2);
|
||
|
|
% d==0 ---> X<0 and absX = -X
|
||
|
|
F = F + (X <= M.*d) + (0 <= absX+X <= 2*maxABSX.*d);
|
||
|
|
% d==1 ---> X>0 and absX = X
|
||
|
|
F = F + (X >= m.*(1-d)) + (0 <= absX-X <= 2*maxABSX.*(1-d));
|
||
|
|
|
||
|
|
F = F + (t - sum(absX)-addsum == 0);
|
||
|
|
end
|
||
|
|
|
||
|
|
else
|
||
|
|
F = max_integer_model([X;-X],t);
|
||
|
|
end
|
||
|
|
varargout{1} = F;
|
||
|
|
varargout{2} = struct('convexity','convex','monotonicity','milp','definiteness','positive','model','integer');
|
||
|
|
varargout{3} = X;
|
||
|
|
end
|
||
|
|
otherwise
|
||
|
|
error('SDPVAR/NORM called with CHAR argument?');
|
||
|
|
end
|
||
|
|
otherwise
|
||
|
|
error('Strange type on first argument in SDPVAR/NORM');
|
||
|
|
end
|
||
|
|
|
||
|
|
function F = findmax(F,M,m,X,t)
|
||
|
|
|
||
|
|
n = length(X);
|
||
|
|
d = binvar(n,1);
|
||
|
|
F = F + (sum(d)==1);
|
||
|
|
F = F + (-(max(M)-min(m))*(1-d) <= t-X <= (max(M)-min(m))*(1-d));
|
||
|
|
kk = [];
|
||
|
|
ii = [];
|
||
|
|
for i = 1:n
|
||
|
|
k = [1:1:i-1 i+1:1:n]';
|
||
|
|
ii = [ii;repmat(i,n-1,1)];
|
||
|
|
kk = [kk;k];
|
||
|
|
Mm = M(k)-m(i);
|
||
|
|
end
|
||
|
|
xii = extsubsref(X,ii);
|
||
|
|
dii = extsubsref(d,ii);
|
||
|
|
xkk = extsubsref(X,kk);
|
||
|
|
F = F + (xkk <= xii+(M(kk)-m(ii)).*(1-dii));
|