Home > utilities > pen2bmi.m

# pen2bmi

## PURPOSE

PEN2BMI converts input structure PEN for PENBMI (as described

## SYNOPSIS

function [bmidata]=pen2bmi(pen, name)

## DESCRIPTION

     PEN2BMI converts input structure PEN for PENBMI (as described
     in PENOPT/PENBMI manual Section 5.2) into a structure accepted by
     PENLAB via BMI or PMI modules, for details see manual or
        modules/BMI/bmi_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.

     See also yalmip2bmi, example_yalmip, bmi_define

     Example:
        bmi=pen2bmi(pen);
        penm = bmi_define(bmi);
        prob = penlab(penm);
        solve(prob);

## CROSS-REFERENCE INFORMATION

This function calls:

This function is called by:

- yalmip2bmi YALMIP2BMI reads the output of YALMIP "export" command and

## SUBFUNCTIONS

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

## SOURCE CODE

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