I wonder why the cvx_optval value is different from the object value obtained through W and R obtained through CVX even though cvx_status is solved

Hello everyone,

my code is

clear
rng(123);

num_target = 18;
num_user = 8;
num_antenna = 12;
noise_power = 10^-11;
p_max = 0.5;
sensing_th = 5 * 10^-5;

user = [370 400;
380 340;
420 300;
470 270;
530 270;
580 300;
620 340;
630 400];

uav = [450 525];

target_x = unifrnd(450, 550, [num_target, 1]);
target_y = unifrnd(590, 610, [num_target, 1]);
target = [target_x target_y];

channel = zeros(num_antenna, num_user);
channel_her = zeros(num_user, num_antenna);
tmp = zeros(num_user, 1);

sum_rate = 0;
sensing_constraint_tmp = 0;
power_constraint_tmp = 0;

for i = 1:num_user
channel(:,i) = get_channel(uav, user(i,:));
channel_her(i,:slight_smile: = transpose(conj(channel(:,i)));
end

[W_t, R_t] = get_init(target);

cvx_begin
variable W(num_antenna, num_antenna, num_user) complex;
variable R(num_antenna, num_antenna) complex;

for k = 1:num_user

    objective_1_tmp = 0;
    alpha_tmp = 0;
    objective_2_tmp = 0;

    for i = 1:num_user
        objective_1_tmp = objective_1_tmp + real(trace(channel(:,k) * channel_her(k,:) * W(:,:,i)));

        if i == k
            continue;
        end

        alpha_tmp = alpha_tmp + real(trace(channel(:,k) * channel_her(k,:) * W_t(:,:,i)));
    end

    alpha_k = alpha_tmp + real(trace(channel(:,k) * channel_her(k,:) * R_t)) + noise_power;
    alpha_k = log(alpha_k) / log(2);

    B = channel(:,k) * channel_her(k,:);
    B = B / alpha_tmp + real(trace(channel(:,k) * channel_her(k,:) * R_t)) + noise_power;
    B = B / log(2);

    for i = 1:num_user

        if i == k
            continue;
        end

        objective_2_tmp = objective_2_tmp + real(trace(B * (W(:,:,i) - W_t(:,:,i))));
    end

    objective_1 = objective_1_tmp + real(trace(channel(:,k) * channel_her(k,:) * R)) + noise_power;
    objective_1 = log(objective_1) / log(2);

    objective_2 = alpha_k + objective_2_tmp + real(trace(B * (R - R_t)));

    rate_tmp = objective_1 - objective_2;
    sum_rate = sum_rate + rate_tmp;

    sensing_constraint_tmp = sensing_constraint_tmp + W(:,:,k);
    power_constraint_tmp = power_constraint_tmp + real(trace(W(:,:,k)));
end

maximize(sum_rate);

subject to

    for k = 1:num_user
        W(:,:,k) == hermitian_semidefinite(num_antenna);
    end

    R == hermitian_semidefinite(num_antenna);
    
    power_constraint = power_constraint_tmp + real(trace(R));
    power_constraint <= p_max;

    for j = 1:num_target

        distance_target = get_distance(uav, target(j,:));
        sterring_target = get_steering(distance_target);
        sterring_target_her = transpose(conj(sterring_target));

        sensing_constraint = real(sterring_target_her * (sensing_constraint_tmp + R) * sterring_target);
        sensing_constraint >= sensing_th * distance_target^2;

    end

cvx_end

then, after cvx_end I just copy my code and modify sum_rate = 0

for k = 1:num_user

    objective_1_tmp = 0;
    alpha_tmp = 0;
    objective_2_tmp = 0;

    for i = 1:num_user
        objective_1_tmp = objective_1_tmp + real(trace(channel(:,k) * channel_her(k,:) * W(:,:,i)));

        if i == k
            continue;
        end

        alpha_tmp = alpha_tmp + real(trace(channel(:,k) * channel_her(k,:) * W_t(:,:,i)));
    end

    alpha_k = alpha_tmp + real(trace(channel(:,k) * channel_her(k,:) * R_t)) + noise_power;
    alpha_k = log(alpha_k) / log(2);

    B = channel(:,k) * channel_her(k,:);
    B = B / alpha_tmp + real(trace(channel(:,k) * channel_her(k,:) * R_t)) + noise_power;
    B = B / log(2);

    for i = 1:num_user

        if i == k
            continue;
        end

        objective_2_tmp = objective_2_tmp + real(trace(B * (W(:,:,i) - W_t(:,:,i))));
    end

    objective_1 = objective_1_tmp + real(trace(channel(:,k) * channel_her(k,:) * R)) + noise_power;
    objective_1 = log(objective_1) / log(2);

    objective_2 = alpha_k + objective_2_tmp + real(trace(B * (R - R_t)));

    rate_tmp = objective_1 - objective_2;
    sum_rate = sum_rate + rate_tmp;

    sensing_constraint_tmp = sensing_constraint_tmp + W(:,:,k);
    power_constraint_tmp = power_constraint_tmp + real(trace(W(:,:,k)));
end

but cvx_optval = 89.8624, sum_rate = 10.4447

cvx_status is ‘Solved’

Thank you for your help

sum_rate is an expression.

CVX variables are populated with their optimal values after cvx_end, but CVX expressions are not necessarily populated with their optimal values after cvx_end. So to get the optimal values of CVX expressions, you need to compute them after cvx_end, starting with the CVX optimal variable values. if you do that you should find that sum_rate will match cvx_optval to within roundoff error. The bottom line is that cvx_optval is the optimal (final) value of sum_rate.

The optimization is performed correctly even though the populated values for the expressions might not be correct. That reflects a CVX design decision. At the expense of some additional computation, CVX could have been written to automatically populate CVX expressions with their final optimal value, but was not designed that way. At minimum, the CVX Users’ Guide should have been clear and explicit about this (design decision), but is not.

Thank you for your answer!!

I found the problem, but I can’t solve it

cvx_begin
expressions sum_rate(num_user, 1)

    expressions objective_1(num_user, 1)
    expressions objective_1_tmp(num_user, 1)
    expressions tmp(num_user, 1)
    expressions tmp_tmp(num_user, 1)

    expressions objective_2(num_user, 1)
    expressions objective_2_tmp(num_user, 1)

    variable W(num_antenna, num_antenna, num_user) complex;
    variable R(num_antenna, num_antenna) complex;

    for k = 1:num_user

        for i = 1:num_user
            objective_1_tmp(k) = objective_1_tmp(k) + real(trace(channel(:,k) * channel_her(k,:) * W(:,:,i)));

            if i == k
                continue;
            end

            alpha_tmp(k) = alpha_tmp(k) + real(trace(channel(:,k) * channel_her(k,:) * W_t(:,:,i)));
        end

        alpha(k) = alpha_tmp(k) + real(trace(channel(:,k) * channel_her(k,:) * R_t)) + noise_power;
        alpha(k) = log(alpha(k)) / log(2);

        B(:,:,k) = channel(:,k) * channel_her(k,:);
        B(:,:,k) = B(:,:,k) / (alpha_tmp(k) + real(trace(channel(:,k) * channel_her(k,:) * R_t)) + noise_power);
        B(:,:,k) = B(:,:,k) / log(2);

        for i = 1:num_user

            if i == k
                continue;
            end

            objective_2_tmp(k) = objective_2_tmp(k) + real(trace(B(:,:,k) * (W(:,:,i) - W_t(:,:,i))));
        end

        tmp(k) = objective_1_tmp(k) + real(trace(channel(:,k) * channel_her(k,:) * R)) + noise_power;
        tmp_tmp(k) = log(tmp(k));
        objective_1(k) = tmp_tmp(k) / log(2);

        objective_2(k) = alpha(k) + objective_2_tmp(k) + real(trace(B(:,:,k) * (R - R_t)));

        sum_rate(k) = objective_1(k) - objective_2(k);

        sensing_constraint_tmp = sensing_constraint_tmp + W(:,:,k);
        power_constraint_tmp = power_constraint_tmp + real(trace(W(:,:,k)));
    end

    maximize(sum(sum_rate));

    subject to

        for k = 1:num_user
            W(:,:,k) == hermitian_semidefinite(num_antenna);
        end

        R == hermitian_semidefinite(num_antenna);
        
        power_constraint = power_constraint_tmp + real(trace(R));
        power_constraint <= p_max;

        for j = 1:num_target

            distance_target = get_distance(uav, target(j,:));
            sterring_target = get_steering(distance_target);
            sterring_target_her = transpose(conj(sterring_target));

            sensing_constraint = real(sterring_target_her * (sensing_constraint_tmp + R) * sterring_target);
            sensing_constraint >= sensing_th * distance_target^2;

        end
cvx_end

this is my modified code

among them,

tmp(k) = objective_1_tmp(k) + real(trace(channel(:,k) * channel_her(k,:slight_smile: * R)) + noise_power;
tmp_tmp(k) = log(tmp(k));

tmp(k) is cvx real affine expression (scalar)

tmp_tmp(k) is cvx concave expression (scalar)

but after cvx_end

tmp(1) is 3.6746e-11, tmp_tmp(1) is -18.4045 but log(tmp(1)) is -24.0270

It is not same.

What exactly is your remaining difficulty?

As I wrote above, you should not rely on the value of any CVX expression after cvx_end. Only CVX variables are “guaranteed” (presuming the problem is solved to optimality) to be populated with their optimal values after cvx_ehd. CVX correctly solves the optimal problem, but does not necessarily correctly report the optimal values of CVX expressions; and the values those expressions do have may be inconsistent with each other (as well as with CVX optimal variable values). Nevertheless, the optimization problem is actually solved with the requisite consistency.

Bottom line: You should IGNORE the values of all CVX expressions after cvx_end. They may or may not be correct. Looking at their values does not provide a check on anything. If you want to know the optimal values of CVX expressions, you need to compute them after cvx_end, starting from CVX variable values. Yes, that may be a hassle, but that’s the way CVX was designed, and there is almots no chance CVX will ever be modified to change that behavior. The one sort of exception is if the entirety of the objective function is a CVX expression, in which case cvx_optval is the optimal value of that expression.

Thank you for your answer!!
What I understand is that the cvx_expressions value is not correct.
but There is a big difference between cvx_optval and sum_rate in the first code I posted even though I didn’t use the cvx_expression variable
Am I misunderstanding cvx_expression??

Anything which is not input data or declared as a (CVX) variable is a CVX expression. That is true whether or not it is declared as an expression. Therefore, sum_rate is an expression, whose value after cvx_end is not necessarily correct. Therefore its value need not match or be consistent with anything. As I wrote before, you should ignore the value of any expression after cvx_end.

In the end, after cvx_end, values other than cvx_variable are not accurate, right?? In my case, values other than W and R are not accurate.

But when I compared the cvx_optval and sum_rate values, I only used W and R to compare
cvx_optval is 89.8624 and sum_rate is 10.4447

Just ignore expressions after cvx_end. If you want to know an expression’s optimal value, compute it starting from variable values. Don’t think of cvx_optval as an expression, think of it as the optimal objective value.

Before submittung a problem to the solver, CVX transforms the problem. After the solver finds the optimal solution, CVX reverses its transformations to populate the variable values and cvx_optval. It doesn’t always reverse the transformations in a way guaranteed to produce optimal expression values. It could have been designed to do so, but wasn’t, much to my chagrin at present.

As far as I understand, cvx_optval is also cvx_expression, so it’s not accurate??
So the the cvx_optval value and the sum_rate value obtained by W and R after cvx_end can be different

Per my previous post, cvx_optval should always be the optimal objective value. Don’t think of it as being an expression. CVX expression values should be considered to be “for entertainment purposes only”, i.e., IGNORED.