Home > utilities > didi2bmi2.m

# didi2bmi2

## PURPOSE

This routine converts input structure PEN for PenBMI (as described

## SYNOPSIS

function [bmidata]=didi2bmi2(pen, name)

## DESCRIPTION

     This routine converts input structure PEN for PenBMI (as described
     in PenOpt/PenBMI manual Section 5.2) into a structure accepted by
     PenLab via BMI2 or PMI modules, for details see manual or
        modules/BMI2/bmi2_define.m.
     Note that the convertor doesn't do any heavy checking on the input
     structure. If there were any inconsistencies in 'pen' it might be
     noticed either here or in bmi2_define().

     Structure 'pen' can be also obtained via YALMIP as internal input
     for PenBMI.

     Example:
        load didi/pen-f4e.mat
        didi
        bmidata = didi2bmi2(pen,'f4e')
        penm = bmi2_define(bmidata);
        prob = penlab(penm);
        prob.solve();
        ...

## CROSS-REFERENCE INFORMATION

This function calls:

This function is called by:

## SUBFUNCTIONS

- function [Ak] = copy_mconstr(dim,nA,nK,A_idx,K_idx,K_jdx,

## SOURCE CODE

    0001 % This routine converts input structure PEN for PenBMI (as described
    0002 % in PenOpt/PenBMI manual Section 5.2) into a structure accepted by
    0003 % PenLab via BMI2 or PMI modules, for details see manual or
    0004 %    modules/BMI2/bmi2_define.m.
    0005 % Note that the convertor doesn't do any heavy checking on the input
    0006 % structure. If there were any inconsistencies in 'pen' it might be
    0007 % noticed either here or in bmi2_define().
    0008 %
    0009 % Structure 'pen' can be also obtained via YALMIP as internal input
    0010 % for PenBMI.
    0011 %
    0012 % Example:
    0013 %    load didi/pen-f4e.mat
    0014 %    didi
    0015 %    bmidata = didi2bmi2(pen,'f4e')
    0016 %    penm = bmi2_define(bmidata);
    0017 %    prob = penlab(penm);
    0018 %    prob.solve();
    0019 %    ...
    0020 %
    0021 function [bmidata]=didi2bmi2(pen, name)
    0022
    0023   if (nargin<=1)
    0024     name='BMI2 from convertor didi2bmi2()';
    0025   end
    0026
    0027   %%%%%%%%%  Convert the data %%%%%%%%%
    0028
    0029   bmidata = [];
    0030   bmidata.name = name;
    0031
    0032   % no of variables
    0033   if (~isfield(pen,'vars') || pen.vars<=0)
    0034     error('Input: wrong or missing vars component in pen.');
    0035   end
    0036   bmidata.Nx = pen.vars;
    0037   Nx = pen.vars;
    0038
    0039   % if present, copy starting point
    0040   if (isfield(pen,'x0'))
    0041     if (isempty(pen.x0) || ~isvector(pen.x0) || length(pen.x0)~=Nx)
    0042       error('Input: starting point x0 is incompatible.');
    0043     end
    0044     bmidata.xinit = pen.x0;
    0045   end
    0046
    0047   % dense vector of the linear part of objective function
    0048   if (isfield(pen,'fobj') && ~isempty(pen.fobj))
    0049     bmidata.c = pen.fobj;
    0050   end
    0051
    0052   % if present, quadratic part of the objective function
    0053   if (isfield(pen,'q_nzs') && ~isempty(pen.q_nzs) && pen.q_nzs>0)
    0054     if (~isfield(pen,'q_row') || ~isfield(pen,'q_col') || ~isfield(pen,'q_val'))
    0055       error('Input: incomplete quadratic part of the objective.');
    0056     end
    0057     H = sparse(pen.q_row+1, pen.q_col+1, pen.q_val,Nx,Nx,pen.Q_nzs);
    0058     % only upper triangle, symmetrize
    0059     bmidata.H = H + triu(H,1)';
    0060   end
    0061
    0062   % block of linear constraints stored in 'pen' in the form Bx<=c
    0063   if (isfield(pen,'constr') && ~isempty(pen.constr) && pen.constr>0)
    0064     if (~isfield(pen,'bi_dim') || ~isfield(pen,'bi_idx') || ...
    0065       ~isfield(pen,'bi_val') || ~isfield(pen,'ci'))
    0066       error('Input: incomplete linear constraints Bx<=c.');
    0067     end
    0068     if (any(pen.bi_dim<0))
    0069       error('Input: bi_dim has negative components.');
    0070     end
    0071
    0072     % convert CCS -> CS
    0073     nnzB=sum(pen.bi_dim);
    0074     brows=[];
    0075     for idx=1:pen.constr
    0076       brows=[brows;idx*ones(pen.bi_dim(idx),1)];
    0077     end
    0078     B = sparse(brows,pen.bi_idx+1,pen.bi_val,pen.constr,Nx,nnzB);
    0079     bmidata.B = B;
    0080     bmidata.ubg = pen.ci;
    0081   end
    0082
    0083   % matrix constraints
    0084   if (isfield(pen,'mconstr') && ~isempty(pen.mconstr) && pen.mconstr>0)
    0085     if (~isfield(pen,'msizes') || any(pen.msizes<1))
    0086       error('Input: msizes missing or wrong.');
    0087     end
    0088
    0089     % linear matrix terms - OK?
    0090     if (isfield(pen,'ai_dim'))
    0091       if (isempty(pen.ai_dim) || any(pen.ai_dim<0) || ...
    0092         ~isfield(pen,'ai_idx') || ...
    0093         ~isfield(pen,'ai_nzs') || any(pen.ai_nzs<0) || ...
    0094         ~isfield(pen,'ai_val') || ~isfield(pen,'ai_col') || ...
    0095         ~isfield(pen,'ai_row'))
    0096         error('Input: incomplete linear matrix terms A_i^k.');
    0097       end
    0098     else
    0099       % linear SDP terms missing? assume that all are empty
    0100       pen.ai_dim=zeros(pen.mconstr,1);
    0101       pen.ai_idx=zeros(1,1);
    0102       pen.ai_nzs=zeros(1,1);
    0103       pen.ai_val=zeros(1,1);
    0104       pen.ai_col=zeros(1,1);
    0105       pen.ai_row=zeros(1,1);
    0106     end
    0107
    0108     % bilinear matrix terms - OK?
    0109     if (isfield(pen,'ki_dim'))
    0110       if (isempty(pen.ki_dim) || any(pen.ki_dim<0) || ...
    0111         ~isfield(pen,'ki_idx') || ~isfield(pen,'kj_idx') || ...
    0112         ~isfield(pen,'ki_nzs') || any(pen.ki_nzs<0) || ...
    0113         ~isfield(pen,'ki_val') || ~isfield(pen,'ki_col') || ...
    0114         ~isfield(pen,'ki_row'))
    0115         error('Input: incomplete bilinear matrix terms K_ij^k.');
    0116       end
    0117     else
    0118       % bilinear SDP terms missing --> just linear SDP, no higher order matrices
    0119       pen.ki_dim=zeros(pen.mconstr,1);
    0120       pen.ki_idx=zeros(1,1);
    0121       pen.kj_idx=zeros(1,1);
    0122       pen.ki_nzs=zeros(1,1);
    0123       pen.ki_val=zeros(1,1);
    0124       pen.ki_col=zeros(1,1);
    0125       pen.ki_row=zeros(1,1);
    0126     end
    0127
    0128     bmidata.Na = pen.mconstr;
    0129     bmidata.A = cell(pen.mconstr,1);
    0130
    0131     % copy one matrix constraint at a time
    0132     midxAstart=1;          % indices to *_nzs() and *_idx() arrays
    0133     midxKstart=1;
    0134     idxA=1;                % indices to *_val, *_col, *_row arrays
    0135     idxK=1;
    0136
    0137     for k=1:pen.mconstr
    0138       midxAend=midxAstart+pen.ai_dim(k)-1;
    0139       midxKend=midxKstart+pen.ki_dim(k)-1;
    0140       nnzAsum=sum(pen.ai_nzs(midxAstart:midxAend));
    0141       nnzKsum=sum(pen.ki_nzs(midxKstart:midxKend));
    0142
    0143       bmidata.A{k} = copy_mconstr(pen.msizes(k),pen.ai_dim(k),pen.ki_dim(k),...
    0144         pen.ai_idx(midxAstart:midxAend), ...
    0145         pen.ki_idx(midxKstart:midxKend), pen.kj_idx(midxKstart:midxKend), ...
    0146         pen.ai_nzs(midxAstart:midxAend), ...
    0147         pen.ai_val(idxA:end), pen.ai_row(idxA:end), pen.ai_col(idxA:end),...
    0148         pen.ki_nzs(midxKstart:midxKend), ...
    0149         pen.ki_val(idxK:end), pen.ki_row(idxK:end), pen.ki_col(idxK:end));
    0150
    0151
    0152       % move indices in *_nzs arrays
    0153       midxAstart=midxAend+1;
    0154       midxKstart=midxKend+1;
    0155       % move indices in *_val arrays
    0156       idxA = idxA+nnzAsum;
    0157       idxK = idxK+nnzKsum;
    0158     end
    0159   end
    0160
    0161 end
    0162
    0163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    0164 % create one matrix constraints from PenBMI data
    0165 % in the format required in BMI2/PMI
    0166 %
    0167 % Input:
    0168 %   dim - dimension of the matrix constraint
    0169 %   nA, nK - number of matrices in linear and bilinear terms
    0170 %   A_idx - dim nA, indices of the linear matrices A_i
    0171 %   K_idx, K_jdx - dim nK, i and j indices of bilinear matrices K_ij
    0172 %   A_nnz - dim nA, number of nonzeros in each given matrix A_i
    0173 %   A_val,col,row - dim sum(A_nnz), matries A_i next to each other
    0174 %     stored in CS upper triangle format, 0-based indices row/col
    0175 %   K_nnz - dim nK, number of nonzeros in each given K_ij
    0176 %   K_val,col,row - dim sum(K_nnz), K_ij matrices, same format as A_i
    0177 %
    0178 function [Ak] = copy_mconstr(dim,nA,nK,A_idx,K_idx,K_jdx,...
    0179   A_nnz,A_val,A_row,A_col,K_nnz,K_val,K_row,K_col)
    0180
    0181   if (nA==0 && nK==0)
    0182     error('Input: neither linear nor bilinear matrices in this constraint.');
    0183   end
    0184
    0185   if (nK==0)
    0186     maxOrder = 1;
    0187     Ak.midx = zeros(maxOrder,nA);
    0188     Ak.midx(1,:) = A_idx(1:nA);
    0189   else
    0190     maxOrder = 2;
    0191     Ak.midx = zeros(maxOrder,nA+nK);
    0192     Ak.midx(1,1:nA) = A_idx(1:nA);   % midx(2,1:nA) = zeroes()
    0193     Ak.midx(1,nA+1:end) = K_idx(1:nK);
    0194     Ak.midx(2,nA+1:end) = K_jdx(1:nK);
    0195   end
    0196
    0197   Ak.Q = cell(nA+nK,1);
    0198   % copy linear terms
    0199   idx = 1;          % index to _val/_row/_col arrays
    0200   for midx=1:nA
    0201     idxend = idx+A_nnz(midx)-1;
    0202     Qi = sparse(A_row(idx:idxend)+1, A_col(idx:idxend)+1, A_val(idx:idxend),...
    0203       dim, dim, A_nnz(midx));
    0204     % symmetrize, was just upper triangle
    0205     Qi = Qi + triu(Qi,1)';
    0206     % swap sign, we want Ak >= 0 (pos. def.) and it was neg. def.
    0207     Ak.Q{midx} = -Qi;
    0208
    0209     idx = idxend+1;
    0210   end
    0211
    0212   % copy bilinear terms
    0213   idx = 1;          % index to _val/_row/_col arrays
    0214   for midx=1:nK
    0215     idxend = idx+K_nnz(midx)-1;
    0216     Qi = sparse(K_row(idx:idxend)+1, K_col(idx:idxend)+1, K_val(idx:idxend),...
    0217       dim, dim, K_nnz(midx));
    0218     % symmetrize, was just upper triangle
    0219     Qi = Qi + triu(Qi,1)';
    0220     % swap sign, we want Ak >= 0 (pos. def.) and it was neg. def.
    0221     Ak.Q{nA+midx} = -Qi;
    0222
    0223     idx = idxend+1;
    0224   end
    0225
    0226 end
    0227