Search code examples
mathematical-optimizationgreedy

Is there an algorithm that clips and redistributes values in an array subject to constraints?


I have an array x of real values x_i. Some of these values are above a threshold constant c and so the values above c need to be clipped, and the clipped amount redistributed to the other elements in the array.

The transformation of the x_i's are subject to the following constraints:

  • x_i < c for all i, where c is a known threshold constant
  • sum(x) needs to be approximately zero (as close to zero as possible)
  • sum(abs(x)) needs to be less than some known constant g

The change in values in x should be minimal, so this is essentially the optimization problem.

I am not sure what type of optimization problem this is, how it can be solved (if at all) or what relevant literature to read. If anyone knows the specific type of optimization problem this is, any algorithms that can solve it, or how I can go about solving it, that would be much appreciated.


Solution

  • So, a high-level model can look like:

    min sum(|x[i]-x0[i]|)
    x[i] <= c
    sum(x[i]) = 0
    sum(|x(i)|) <= g
    

    Some code to test this out:

    import cvxpy as cv
    import numpy as np
    
    n = 20  
    c = 7 # x <= c
    g = 80 # sum(abs(x)) <= g
    x0 = np.random.default_rng(123).uniform(-10,+10,n)
    print(f"x0:\n{x0}")
    
    x = cv.Variable(n)
    
    prob = cv.Problem(
        cv.Minimize(cv.sum(cv.abs(x-x0))),
        [x<=c, cv.sum(x)==0, cv.sum(cv.abs(x)) <= g]
    )
    prob.solve()
    
    print(f"x:\n{x.value}")
    print(f"sum(x)   :{sum(x.value)}\nsum(|x|) :{sum(np.abs(x.value))}\nmax(x)   :{max(x.value)}") 
    

    Output:

    x0:
    [ 3.64703726 -8.92357962 -5.59280254 -6.31256379 -6.48188198  6.24189013
      8.46689996 -4.46851204  6.39509123  7.79785386  0.2594091  -5.10070798
      6.48483192 -5.72474073  4.82934104  2.59880409  8.54814517 -5.36183623
      5.98250257  0.36330074]
    x:
    [ 2.42801305 -7.52326449 -4.65566667 -5.28888531 -5.43657677  4.22054525
      5.19677348 -3.65389826  4.31045304  4.97952779  0.10872304 -4.2185185
      4.3617407  -4.77234867  3.28537387  1.66750902  5.21912779 -4.45084134
      4.0620259   0.16018709]
    sum(x)   :4.85722573273506e-15
    sum(|x|) :79.99999999776362
    max(x)   :5.219127785064835