[37] | 1 | function varargout = nnz(varargin) |
---|
| 2 | %NNZ (overloaded) |
---|
| 3 | % |
---|
| 4 | % n = nnz(X) |
---|
| 5 | % |
---|
| 6 | % NNZ applied to a constraint counts the number of satisfied constraints. |
---|
| 7 | % |
---|
| 8 | % The NNZ operator is implemented using the concept of nonlinear operators |
---|
| 9 | % in YALMIP. NNZ(X) creates a new so called derived variable that can be |
---|
| 10 | % treated as any other variable in YALMIP. When SOLVESDP is issued, |
---|
| 11 | % logic constraints are added to the problem to model the NNZ operator. |
---|
| 12 | |
---|
| 13 | |
---|
| 14 | % Author Johan Löfberg |
---|
| 15 | % $Id: nnz.m,v 1.6 2006/05/15 20:00:39 joloef Exp $ |
---|
| 16 | |
---|
| 17 | switch class(varargin{1}) |
---|
| 18 | |
---|
| 19 | case 'constraint' |
---|
| 20 | varargout{1} = yalmip('addextendedvariable','nnz',varargin{1}); |
---|
| 21 | |
---|
| 22 | case 'char' |
---|
| 23 | t = varargin{2}; |
---|
| 24 | x = varargin{3}; |
---|
| 25 | switch varargin{1} |
---|
| 26 | case 'graph' |
---|
| 27 | x = set(x); |
---|
| 28 | if is(x,'elementwise') |
---|
| 29 | x = sdpvar(x); |
---|
| 30 | x = x(:); |
---|
| 31 | [M,m] = derivebounds(x); |
---|
| 32 | delta = binvar(length(x),1); |
---|
| 33 | F = set(x >= m.*(1-delta)) + set(sum(delta) == t); |
---|
| 34 | elseif is(x,'equality') |
---|
| 35 | x = sdpvar(x); |
---|
| 36 | x = x(:); |
---|
| 37 | [M,m,infbound] = derivebounds(x); |
---|
| 38 | if infbound |
---|
| 39 | warning('You have unbounded variables in IMPLIES leading to a lousy big-M relaxation.'); |
---|
| 40 | end |
---|
| 41 | delta = binvar(length(x),1); |
---|
| 42 | F = set(M.*(1-delta) >= x >= m.*(1-delta)) + set(sum(delta) == t); |
---|
| 43 | else |
---|
| 44 | error('Constraint type not supported in cardinality. Make a feature request'); |
---|
| 45 | end |
---|
| 46 | varargout{1} = F; |
---|
| 47 | varargout{2} = struct('convexity','concave','monotonicity','none','definiteness','none'); |
---|
| 48 | varargout{3} = x; |
---|
| 49 | |
---|
| 50 | otherwise |
---|
| 51 | x = set(x); |
---|
| 52 | if is(x,'elementwise') |
---|
| 53 | x = sdpvar(x); |
---|
| 54 | x = x(:); |
---|
| 55 | [M,m,infbound] = derivebounds(x); |
---|
| 56 | if infbound |
---|
| 57 | warning('You have unbounded variables in NNZ leading to a lousy big-M relaxation.'); |
---|
| 58 | end |
---|
| 59 | n = length(x); |
---|
| 60 | deltaD = binvar(n,1); |
---|
| 61 | deltaU = binvar(n,1); |
---|
| 62 | if all(ismember(getvariables(x),[yalmip('intvariables') yalmip('binvariables')])) |
---|
| 63 | % If an integer constraint not holds, it has to be |
---|
| 64 | % epsilon violated |
---|
| 65 | F = set((M+1e-4).*(1-deltaU)-1e-4 >= x >= m.*(1-deltaD)); |
---|
| 66 | else |
---|
| 67 | % User has to think harder him self |
---|
| 68 | F = set((M).*(1-deltaU) >= x >= m.*(1-deltaD)); |
---|
| 69 | end |
---|
| 70 | F = F + set(sum(deltaD) == t); |
---|
| 71 | F = F + set(deltaU + deltaD == 1); |
---|
| 72 | F = F + set(0 <= t <= n); |
---|
| 73 | elseif is(x,'equality') |
---|
| 74 | x = sdpvar(x); |
---|
| 75 | x = x(:); |
---|
| 76 | n = length(x); |
---|
| 77 | [M,m] = derivebounds(x); |
---|
| 78 | deltaZ = binvar(n,1); |
---|
| 79 | deltaNZU = binvar(n,1); |
---|
| 80 | deltaNZD = binvar(n,1); |
---|
| 81 | eps = 1e-4; |
---|
| 82 | % deltaZ forces x to be zero |
---|
| 83 | % deltaZU 1 is x > eps |
---|
| 84 | % deltaZU 1 is x < -eps |
---|
| 85 | F = set(M.*(1-deltaZ) >= x >= m.*(1-deltaZ)); |
---|
| 86 | F = set((M+eps).*deltaNZU-eps>= x >= eps + (m-eps).*deltaNZD); |
---|
| 87 | F = F + set(sum(deltaZ) == t); |
---|
| 88 | F = F + set(deltaZ + deltaNZU + deltaNZD == 1); |
---|
| 89 | F = F + set(0 <= t <= n); |
---|
| 90 | else |
---|
| 91 | error('Constraint type not supported in cardinality. Make a feature request'); |
---|
| 92 | end |
---|
| 93 | varargout{1} = F; |
---|
| 94 | varargout{2} = struct('convexity','milp','monotonicity','milp','definiteness','milp'); |
---|
| 95 | varargout{3} = x; |
---|
| 96 | end |
---|
| 97 | otherwise |
---|
| 98 | end |
---|