matlabcvx

Why in the content of cvx, subs() does not work?


TLDR I wrote a code to solve a SDP problem. I used subs to change syms into numerical value before cvx content and I did see the numerical value after I printed out the variables. But whos() did show that the variable is still syms type which I think might be the key point where I went wrong. The error message shows like this:

Unable to convert 'cvx' to 'sym'.

It went wrong at the line trace(rhot*X_ele(:,:,i)) == value(i); where rhot is symbolic instead of numeric.

Details I'm trying to write a SDP problem as follows:

function [res] = NH_SDP(rhot,p,value,t)
dim = size(rhot,1);
for i = 1:p
    drhot(:,:,i) = diff(rhot,t(i));
end
drhot = subs(drhot,t,value);
rhot = subs(rhot,t,value);
rhott = kron(eye(p),rhot);

% cvx process
cvx_begin sdp
%     cvx part
    variable L_ele(dim,dim,(1+p)*p/2) hermitian;
    variable X_ele(dim,dim,p) hermitian;
    cnt = 1;
    for i = 1:p
        for j = i:p
            if i == j
                L((i-1)*dim+1:i*dim,(j-1)*dim+1:j*dim) = L_ele(:,:,cnt);
                cnt = cnt + 1;
            else
                L((i-1)*dim+1:i*dim,(j-1)*dim+1:j*dim) = L_ele(:,:,cnt);
                L((j-1)*dim+1:j*dim,(i-1)*dim+1:i*dim) = L_ele(:,:,cnt);
                cnt = cnt + 1;
            end
        end
    end
    for i = 1:p
        X((i-1)*dim+1:i*dim,1:dim) = X_ele(:,:,i);
    end
    for i = 1:p
        X2(1:dim,(i-1)*dim+1:i*dim) = X_ele(:,:,i);
    end
% rhott = [[0,    0,    0, 0, 0,    0,    0, 0]
% [0,  1/2, 7/20, 0, 0,    0,    0, 0]
% [0, 7/20,  1/2, 0, 0,    0,    0, 0]
% [0,    0,    0, 0, 0,    0,    0, 0]
% [0,    0,    0, 0, 0,    0,    0, 0]
% [0,    0,    0, 0, 0,  1/2, 7/20, 0]
% [0,    0,    0, 0, 0, 7/20,  1/2, 0]
% [0,    0,    0, 0, 0,    0,    0, 0]];
    rhott = double(rhott);
    rhot = double(rhot);
    drhot = double(drhot);
    minimize(trace(rhott*L));
    subject to
%     rhot = [0 0 0 0;0 1/2 7/20 0;0 7/20 1/2 0;0 0 0 0];
%     drhot
        for i =1:p
            trace(rhot*X_ele(:,:,i)) == value(i);
        end
        for i = 1:p
            for j = 1:p
                if i == j
                    trace(drhot(:,:,i)*X_ele(:,:,j)) == 1;
                else
                    trace(drhot(:,:,i)*X_ele(:,:,j)) == 0;
                end
            end
        end
%         semidefinit constraint.
        [L X; X2 eye(dim)] >= 0;
cvx_end
res = cvx_optval;
X_ele
end

There are three line in the above code:

    rhott = double(rhott);
    rhot = double(rhot);
    drhot = double(drhot);

If I delete those three lines, there will be error Unable to convert 'cvx' to 'sym'. while my rhot have already changed into numerical value by subs function and I print it out to see numerical numbers even though whos function show that the type of rhot is still syms.


Solution

  • To cite the documentation on subs():

    snew = subs(s,old,new) returns a copy of s, replacing all occurrences of old with new, and then evaluates s. Here, s is an expression of symbolic scalar variables or a symbolic function, and old specifies the symbolic scalar variables or symbolic function to be substituted.

    emphasis mine. In other words: subs() changes your symbolic expression to a new symbolic expression.
    double() on the other hand, converts whatever you feed it to a type double, i.e. a numeric value. rhott thus initially contains a symbolic value, even if that is a number. double(rhott) then evaluates it to a numeric number, rather than a symbolic one.


    I presume the problem is here

    drhot = subs(drhot,t,value);
    rhot = subs(rhot,t,value);
    rhott = kron(eye(p),rhot);
    

    You're substituting all occurrences of t within drhot with value, and then again on rhot. if drhot is already symbolic, i.e. if the inputs rhot, value, t are symbolic, this makes sense and indeed a double call will make your system numeric, rather than symbolic. If, on the other hand, all inputs are numeric, subs() unnecessarily converts everything to symbolic variables, slowing execution speed.