XiongPengNUS / rsome

Robust Stochastic Optimization Made Easy
GNU General Public License v3.0
282 stars 54 forks source link

Problem with adding constraints #33

Closed GalPerelman closed 1 year ago

GalPerelman commented 1 year ago

Hi, I'm experiencing strange behavior with the package and wonder whether it is a mistake of mine or a bug Consider the following LHS matrix and RHS vector:

lhs = 
[[250. 250. 400.   0.   0.   0.   0.   0.   0.   0.   0.   0. 300.   0.   0.   0.]
 [250. 250. 400. 250. 250. 400.   0.   0.   0.   0.   0.   0. 300. 300.   0.   0.]
 [250. 250. 400. 250. 250. 400. 250. 250. 400.   0.   0.   0. 300. 300. 300.   0.]
 [250. 250. 400. 250. 250. 400. 250. 250. 400. 250. 250. 400. 300. 300. 300. 300.]]

 b=
 [[-868.37999983]
 [-741.14999983]
 [-612.89999983]
 [ -38.48      ]]

When I try to add the constraint to my model as:

model.st(lhs @ x >= b)

Then, by using model.do_math() I get a matrix that duplicates the LHS for each value of the RHS vector (see below) instead of assigning the RHS values to the corresponding rows of the LHS matrix

primal = model.do_math()
print(primal.show())
         x1       x2       x3       x4       x5       x6       x7       x8       x9      x10      x11      x12      x13      x14      x15      x16      x17 sense constant
Obj   1.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000     -        -
LC1   0.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000    0.000    0.000    0.000    <=  868.380
LC2   0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000 -300.000    0.000    0.000    <=  868.380
LC3   0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000 -300.000 -300.000 -300.000    0.000    <=  868.380
LC4   0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -300.000 -300.000 -300.000 -300.000    <=  868.380
LC5   0.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000    0.000    0.000    0.000    <=  741.150
LC6   0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000 -300.000    0.000    0.000    <=  741.150
LC7   0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000 -300.000 -300.000 -300.000    0.000    <=  741.150
LC8   0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -300.000 -300.000 -300.000 -300.000    <=  741.150
LC9   0.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000    0.000    0.000    0.000    <=  612.900
LC10  0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000 -300.000    0.000    0.000    <=  612.900
LC11  0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000 -300.000 -300.000 -300.000    0.000    <=  612.900
LC12  0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -300.000 -300.000 -300.000 -300.000    <=  612.900
LC13  0.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000    0.000    0.000    0.000    <=   38.480
LC14  0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000    0.000    0.000    0.000 -300.000 -300.000    0.000    0.000    <=   38.480
LC15  0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000    0.000    0.000    0.000 -300.000 -300.000 -300.000    0.000    <=   38.480
LC16  0.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -250.000 -250.000 -400.000 -300.000 -300.000 -300.000 -300.000    <=   38.480
LC17 -1.000  100.000   95.000  172.000  100.020   95.019  172.034  100.040   95.038  172.069  100.060   95.057  172.103  126.000  126.000  126.000  126.000    <=   -0.000
UB      inf    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000    1.000     -        -
LB     -inf    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000    0.000     -        -
Type      C        C        C        C        C        C        C        C        C        C        C        C        C        C        C        C        C     -        -
GalPerelman commented 1 year ago

Update: In the above example, the shape of b is in form of (n, 1)

print(b.shape)
>>> (4, 1)

When reshaping the vector to numpy (n, ) the problem is solved. For example:

b = np.squeeze(b)
print(b.shape)
>>> (4, )
XiongPengNUS commented 1 year ago

Hi @GalPerelman, please note that RSOME is consistent with NumPy array operations, so in the example you provided, the left-hand-side is a one-dimensional array, which is recognized as a one-row array, with the shape to be (4, ). The right-hand-side array is a two-dimensional array, and its shape is (4, 1). According to the broadcasting rule of NumPy arrays, operations between the two arrays gives a two-dimensional array and its shape is (4, 4). That is why the constraints are duplicated. Please check this figure: https://numpy.org/doc/stable/_images/broadcasting_4.png

To fix this problem, you can reshape or squeeze the right-hand-side vector to be (4, ). Alternatively, we can reshape the left-hand-side array from (4, ) to (4, 1), then element-wise constraints are constructed without using broadcasting.

GalPerelman commented 1 year ago

@XiongPengNUS Thank you for the clarification about the reasons behind this behavior.