Invalid quadratic form: must be a scalar (trace minimization)

All, now I have a problem using CVX to solve the following trace optimization:

A = rand(5,5);
    variable LM(5,4);
    minimize( trace(LM'*A*LM) );


??? Error using ==> cvx.mtimes at 127
Disciplined convex programming error:
    Invalid quadratic form: must be a scalar.
Error in ==> testtrace at 7
    minimize( trace(LM'*A*LM) );

could anybody tell me how to modify it to work for equivalent goal? THANKS!

I see two problems. First, the quadratic form x^TAx is convex only for A positive semidefinite. But suppose A were positive semidefinite (and for simplicity LM\in R^5). The second problem is that you would need to use quad_form(LM,A) rather than LM'*A*LM for cvx to recognize it. See page 60 of the cvx user guide.

I’m afraid Bien’s proposal to use quad_form will not work here, at least not immediately, because the quadratic form is not a scalar. The quadratic form CVX is complaining about is LM'*A*LM. This is a 4x4 matrix whose off-diagonal terms violate the DCP ruleset (and besides, they are non-convex). Even though those non-convex terms are eventually discarded by trace(), CVX has no way of knowing that.

However, if A is positive definite, you can try this: let R = chol(A) be the Cholesky factor of A, so the objective can be rewritten trace(LM'*R'*R*LM). Then this is equivalent to sum_square(R*LM).

Another simple way to handle it is

tmp = 0;
for k = 1 : 4,
    tmp = tmp + LM(:,k)'*A*LM(:,k);

In this case, you can use quad_form instead per Bien’s suggestion.

1 Like

Thank mcg and Bien for your kind helps!

is your suggestion of sum_square(R*LM) work if A is complex?

       variables alphas(3) nonnegative ;
      % y1 = trace(alphas' * G1*K*G1' * alphas);
      % G1,K are 3X3 matrices, 
         [R,p] = chol(K);
       y1  = sum_square(R*G1*alphas);

@mcg, I tried this, but it seems sum_square() doesn’t return a scalar if operated on matrices.
Any idea?

Use sum(sum_sq(R*LM))

I actually used reshape() to vectorize the Matrix.
But I wanted to raise it as maybe it should be fixed in code.
Namely thought maybe @mcg intended it to generate scalar for any input while it is not.

Thank You.

P. S.
Documentation say sum_square() is equivalent of sum(square()) while square(), according to documentation, operates on Scalars. This should be clarified as well.

Good catch, Royi, thanks. Both you and Mark arrived at equivalent correct answers.

sum_square() is indeed equivalent to sum(square()). When applied to matrices, square() operates elementwise. Then, when that matrix is passed to sum(), it is summed over a single dimension, leaving a vector. That summing behavior is precisely equivalent to how Matlab does it with numerical matrices, and we seek to preserve Matlab’s semantics when possible.

Now, that said, sum_square produces a somewhat different model than sum(square()) does. That’s because with square(), it creates an individual 2x2 LMI for each element to implement a square. However, with sum_square, it can use second-order cones that span the entire summing dimension. I don’t know if there will be a significant difference in numerical performance, but this will make the sum_square model a bit smaller.

First, you’re welcome.
Though you’re the we should thank for this great program - CVX.

I understood your description of the internals.
Yet I didn’t get if that the behave you planned or something should be fixed.

The documentation should reflect what you wrote above (Now it seems square() would work on Scalars only (While it work on arrays in element wise manner).

Thank You.