/cvx/builtins/@cvx/times.m
http://github.com/tcdoan/portfolioOptimization · Objective C · 294 lines · 259 code · 35 blank · 0 comment · 54 complexity · 29c064cdd081dd160f639ecf155cd6e9 MD5 · raw file
- function z = times( x, y, oper )
- % Disciplined convex programming information for TIMES:
- % In general, disciplined convex programs must obey the "no-product
- % rule" which states that two non-constant expressions cannot be
- % multiplied together. Under this rule, the following combinations
- % are allowed:
- % {constant} .* {non-constant} {non-constant} .* {constant}
- % Furthermore, if the non-constant expression is nonlinear, then
- % the constant term must be real.
- %
- % A lone exception to the no-product rule is made for quadratic
- % forms: two affine expressions may be multiplied together if the
- % result is convex or concave. For example, the construction
- % variable x(n)
- % x.*x <= 1;
- % would be permitted because each element of x.*x is convex.
- %
- % Disciplined geometric programming information for TIMES:
- % Both terms in a multiplication must have the same log-curvature,
- % so the following products are permitted:
- % {log-convex} .* {log-convex} {log-concave} .* {log-concave}
- % {log-affine} .* {log-affine}
- % Note that log-affine expressions are both log-convex and
- % log-concave.
- %
- % For vectors, matrices, and arrays, these rules are verified
- % indepdently for each element.
- error( nargchk( 2, 3, nargin ) );
- if nargin < 3, oper = '.*'; end
- %
- % Check sizes
- %
- sx = size( x );
- sy = size( y );
- xs = all( sx == 1 );
- ys = all( sy == 1 );
- if xs,
- sz = sy;
- elseif ys,
- sz = sx;
- elseif ~isequal( sx, sy ),
- error( 'Matrix dimensions must agree.' );
- else
- sz = sx;
- end
- nn = prod( sz );
- if nn == 0,
- z = zeros( sz );
- return
- end
- %
- % Determine the computation methods
- %
- persistent remap_m remap_l remap_r
- if isempty( remap_r ),
- % zero .* valid, valid .* zero, constant .* constant
- temp_1 = cvx_remap( 'constant' );
- temp_2 = cvx_remap( 'zero' );
- temp_3 = temp_2' * cvx_remap( 'valid' );
- remap_1 = ( temp_1' * temp_1 ) | temp_3 | temp_3';
- remap_1n = ~remap_1;
- % constant / nonzero, zero / log-concave, zero / log-convex
- temp_4 = temp_1 & ~temp_2;
- remap_1r = ( temp_1' * temp_4 ) | ( temp_2' * cvx_remap( 'log-valid' ) );
- remap_1rn = ~remap_1r;
- % constant * affine, real * convex/concave/log-convex, positive * log-concave
- temp_5 = cvx_remap( 'real' );
- temp_6 = cvx_remap( 'positive' );
- temp_7 = cvx_remap( 'affine' );
- temp_1n = ~temp_1;
- temp_8 = cvx_remap( 'log-concave' ) & temp_1n;
- remap_2 = ( temp_1' * temp_7 ) | ...
- ( temp_5' * cvx_remap( 'convex', 'concave', 'log-convex' ) ) | ...
- ( temp_6' * temp_8 );
- remap_2 = remap_2 & remap_1n;
- % real / log-concave, positive / log-convex
- temp_9 = cvx_remap( 'log-convex' ) & temp_1n;
- remap_2r = ( temp_5' * temp_8 ) | ...
- ( temp_6' * temp_9 );
- remap_2r = remap_2r & remap_1rn;
-
- % Affine * constant, convex/concave/log-convex * real, log-concave * positive
- remap_3 = remap_2';
- % Affine / nonzero, convex/concave/log-convex / nzreal, log-concave / positive
- remap_3r = remap_3;
- remap_3r(:,2) = 0;
-
- % Affine * affine
- remap_4 = temp_7 & ~temp_1;
- remap_4 = remap_4' * +remap_4;
- % log-concave * log-concave, log-convex * log-convex
- remap_5 = ( temp_8' * +temp_8 ) | ( temp_9' * +temp_9 );
- % log-concave / log-convex, log-convex / log-concave
- remap_5r = temp_8' * +temp_9;
- remap_5r = remap_5r | remap_5r';
-
- remap_m = remap_1 + 2 * remap_2 + 3 * remap_3 + 4 * remap_4 + 5 * remap_5;
- remap_r = remap_1r + 2 * remap_2r + 3 * remap_3r + 5 * remap_5r;
- remap_r(:,2) = 0;
- remap_l = remap_r';
- end
- switch oper,
- case '.*',
- remap = remap_m;
- r_recip = 0;
- l_recip = 0;
- case './',
- remap = remap_r;
- r_recip = 1;
- l_recip = 0;
- case '.\',
- remap = remap_l;
- r_recip = 0;
- l_recip = 1;
- end
- vx = cvx_classify( x );
- vy = cvx_classify( y );
- vr = remap( vx + size( remap, 1 ) * ( vy - 1 ) );
- vu = sort( vr(:) );
- vu = vu([true;diff(vu)~=0]);
- nv = length( vu );
- if vu(1) == 1 && nv > 1,
- vr(vr==1) == vu(2);
- nv = nv - 1;
- vu(1) = [];
- end
- %
- % Process each computation type separately
- %
- x = cvx( x );
- y = cvx( y );
- xt = x;
- yt = y;
- if nv ~= 1,
- z = cvx( sz, [] );
- end
- for k = 1 : nv,
- %
- % Select the category of expression to compute
- %
- if nv ~= 1,
- t = vr == vu( k );
- if ~xs,
- xt = cvx_subsref( x, t );
- sz = size( xt );
- end
- if ~ys,
- yt = cvx_subsref( y, t );
- sz = size( yt );
- end
- end
- %
- % Apply the appropriate computation
- %
- switch vu( k ),
- case 0,
- % Invalid
- error( 'Disciplined convex programming error:\n Cannot perform the operation: {%s} %s {%s}', cvx_class( xt, true, true, true ), oper, cvx_class( yt, true, true, true ) );
-
- case 1,
-
- % constant .* constant
- xb = cvx_constant( xt );
- yb = cvx_constant( yt );
- if l_recip,
- cvx_optval = xb .\ yb;
- elseif r_recip,
- cvx_optval = xb ./ yb;
- else
- cvx_optval = xb .* yb;
- end
- if nnz( isnan( cvx_optval ) ),
- error( 'Disciplined convex programming error:\n This expression produced one or more invalid numeric values (NaNs).', 1 ); %#ok
- end
- cvx_optval = cvx( cvx_optval );
- case 2,
- % constant .* something
- xb = cvx_constant( xt );
- if l_recip, xb = 1.0 ./ xb; end
- yb = yt;
- if r_recip && nnz( xb ), yb = exp( - log( yb ) ); end
- yb = yb.basis_;
- if ~xs,
- nn = numel( xb );
- if ys,
- xb = cvx_reshape( xb, [ 1, nn ] );
- if issparse( yb ) && ~issparse( xb ),
- xb = sparse( xb );
- end
- else
- n1 = 1 : nn;
- xb = sparse( n1, n1, xb( : ), nn, nn );
- end
- end
- cvx_optval = cvx( sz, yb * xb );
- case 3,
- % something .* constant
- yb = cvx_constant( yt );
- if r_recip, yb = 1.0 ./ yb; end
- xb = xt;
- if l_recip && any( xb ), xb = exp( - log( xb ) ); end
- xb = xb.basis_;
- if ~ys,
- nn = numel( yb );
- if xs,
- yb = cvx_reshape( yb, [ 1, nn ] );
- if issparse( xb ) && ~issparse( yb ),
- yb = sparse( yb );
- end
- else
- n1 = 1 : nn;
- yb = sparse( n1, n1, yb( : ), nn, nn );
- end
- end
- cvx_optval = cvx( sz, xb * yb );
- case 4,
- % affine .* affine
- nn = prod( sz );
- xA = xt.basis_; yA = yt.basis_;
- if xs && ~ys, xA = xA( :, ones( 1, nn ) ); end
- if ys && ~xs, yA = yA( :, ones( 1, nn ) ); end
- mm = max( size( xA, 1 ), size( yA, 1 ) );
- if size( xA, 1 ) < mm, xA( mm, end ) = 0; end
- if size( yA, 1 ) < mm, yA( mm, end ) = 0; end
- xB = xA( 1, : ); xA( 1, : ) = 0;
- yB = yA( 1, : ); yA( 1, : ) = 0;
- cyA = conj( yA );
- alpha = sum( real( xA .* yA ), 1 ) ./ max( sum( cyA .* yA, 1 ), realmin );
- adiag = sparse( 1 : nn, 1 : nn, alpha, nn, nn );
- if all( sum( abs( xA - cyA * adiag ), 2 ) <= 2 * eps * sum( abs( xA ), 2 ) ),
- beta = xB - alpha .* conj( yB );
- alpha = reshape( alpha, sz );
- if isreal( y ),
- cvx_optval = alpha .* square( y ) + reshape( beta, sz ) .* y;
- elseif all( abs( beta ) <= 2 * eps * abs( xB ) ),
- cvx_optval = alpha .* square_abs( y );
- else
- error( 'Disciplined convex programming error:\n Invalid quadratic form(s): product is not real.\n', 1 ); %#ok
- end
- else
- error( 'Disciplined convex programming error:\n Invalid quadratic form(s): not a square.\n', 1 ); %#ok
- end
- case 5,
- % posynomial .* posynomial
- xb = log( xt );
- if l_recip, xb = - xb; end
- yb = log( yt );
- if r_recip, yb = - yb; end
- cvx_optval = exp( xb + yb );
- otherwise,
- error( 'Shouldn''t be here.' );
- end
- %
- % Store the results
- %
- if nv == 1,
- z = cvx_optval;
- else
- z = cvx_subsasgn( z, t, cvx_optval );
- end
- end
- % Copyright 2010 Michael C. Grant and Stephen P. Boyd.
- % See the file COPYING.txt for full copyright information.
- % The command 'cvx_where' will show where this file is located.