1

I have a variable made of 961 elements. And I have a constraint like this: only 8 elements of the variable are nonzero, and the others are 0. I don't know how to express this constraint in cvxpy. I tried this:

import cvxpy as cp
K = cp.Variable(961, integer=Ture)    
s = 0    
constraint = [cp.sum([s+1 for t in K if t!=0])==8]    

But I got the following error:

Exception: Cannot evaluate the truth value of a constraint or chain constraints, e.g., 1 >= x >= 0.

1 Answers1

0

Let's look at this mathematically.

Problem: You have integer variables x[i] ∈ {0,1,2,...,N} and you want to allow only K of them to be nonzero.

We can do this by introducing a parallel binary variable b[i] ∈ {0,1} that indicates whether x[i] is pinned to zero. I use the convention:

  b[i] = 0 => x[i] = 0
  b[i] = 1 => x[i] ∈ {0,1,2,...,N}

This can be written simply as a set of constraints:

  x[i] <= N*b[i]
  sum(i,b[i]) = K

If you want to use the slightly different definition:

  b[i] = 0 => x[i] = 0
  b[i] = 1 => x[i] ∈ {1,2,...,N}

then we need:

  x[i] <= N*b[i]
  x[i] >= b[i]
  sum(i,b[i]) = K

If the integer variables are: x[i] ∈ {-N,...,-2,-1,0,1,2,...,N} then we can do:

  x[i] <= N*b[i]
  x[i] >= -N*b[i]
  sum(i,b[i]) = K

I assume that CVXPY generates the same thing when you say:

  abs(x) <= N*b
  sum(b) == K

(The condition abs(x[i]) >= b[i] is a little bit more messy to linearize in this case).

This should not be too difficult to transcribe into a CVXPY model. Note that we need this explicit upper bound N on x[i]. Make it not too large.

Erwin Kalvelagen
  • 15,677
  • 2
  • 14
  • 39