From 89da4e4bd20539a03008513e7babee608485090c Mon Sep 17 00:00:00 2001 From: Jonathan Berthias Date: Thu, 29 Aug 2024 23:23:11 +0200 Subject: [PATCH] Support norm1 atom (#35) Gurobi only handles vector norms, so we have to ensure we always use 1D arrays when forwarding to `numpy` and/or `cvxpy` since they also have matrix norms. Part of #23 --- src/cvxpy_gurobi/__init__.py | 9 ++++ .../snapshots/all__lp_genexpr_norm1_0__0.txt | 28 ++++++++++ .../snapshots/all__lp_genexpr_norm1_10__0.txt | 34 ++++++++++++ .../snapshots/all__lp_genexpr_norm1_11__0.txt | 36 +++++++++++++ .../snapshots/all__lp_genexpr_norm1_12__0.txt | 43 +++++++++++++++ .../snapshots/all__lp_genexpr_norm1_13__0.txt | 53 +++++++++++++++++++ .../snapshots/all__lp_genexpr_norm1_14__0.txt | 45 ++++++++++++++++ .../snapshots/all__lp_genexpr_norm1_15__0.txt | 47 ++++++++++++++++ .../snapshots/all__lp_genexpr_norm1_1__0.txt | 30 +++++++++++ .../snapshots/all__lp_genexpr_norm1_2__0.txt | 29 ++++++++++ .../snapshots/all__lp_genexpr_norm1_3__0.txt | 31 +++++++++++ .../snapshots/all__lp_genexpr_norm1_4__0.txt | 28 ++++++++++ .../snapshots/all__lp_genexpr_norm1_5__0.txt | 30 +++++++++++ .../snapshots/all__lp_genexpr_norm1_6__0.txt | 29 ++++++++++ .../snapshots/all__lp_genexpr_norm1_7__0.txt | 31 +++++++++++ .../snapshots/all__lp_genexpr_norm1_8__0.txt | 33 ++++++++++++ .../snapshots/all__lp_genexpr_norm1_9__0.txt | 37 +++++++++++++ .../snapshots/all__lp_genexpr_norm2_0__0.txt | 34 ++++++++++++ .../snapshots/all__lp_genexpr_norm2_1__0.txt | 38 +++++++++++++ tests/test_problems.py | 30 +++++++++++ 20 files changed, 675 insertions(+) create mode 100644 tests/snapshots/all__lp_genexpr_norm1_0__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_10__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_11__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_12__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_13__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_14__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_15__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_1__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_2__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_3__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_4__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_5__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_6__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_7__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_8__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm1_9__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm2_0__0.txt create mode 100644 tests/snapshots/all__lp_genexpr_norm2_1__0.txt diff --git a/src/cvxpy_gurobi/__init__.py b/src/cvxpy_gurobi/__init__.py index a60d015..d7111d2 100644 --- a/src/cvxpy_gurobi/__init__.py +++ b/src/cvxpy_gurobi/__init__.py @@ -599,6 +599,15 @@ def visit_multiply(self, mul: multiply) -> Any: def visit_NegExpression(self, node: NegExpression) -> Any: return -self.visit(node.args[0]) + def visit_norm1(self, node: cp.norm1) -> Any: + (x,) = node.args + if isinstance(x, cp.Constant): + return np.linalg.norm(x.value.ravel(), 1) + arg = self.translate_into_variable(x) + varargs = [arg] if isinstance(arg, gp.Var) else arg.reshape(-1).tolist() + norm = gp.norm(varargs, 1) + return self.make_auxilliary_variable_for(norm, "norm1", lb=0) + def visit_power(self, node: power) -> Any: power = self.visit(node.p) if power != 2: diff --git a/tests/snapshots/all__lp_genexpr_norm1_0__0.txt b/tests/snapshots/all__lp_genexpr_norm1_0__0.txt new file mode 100644 index 0000000..dd54b5b --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_0__0.txt @@ -0,0 +1,28 @@ +CVXPY +Minimize + norm1(x) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 +Subject To + R0: - C0 + C1 <= 0 + R1: - C0 - C1 <= 0 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Minimize + 0 x + norm1_1 +Subject To +Bounds + x free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_10__0.txt b/tests/snapshots/all__lp_genexpr_norm1_10__0.txt new file mode 100644 index 0000000..dec4d79 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_10__0.txt @@ -0,0 +1,34 @@ +CVXPY +Minimize + norm1(x) + norm1([ 1. -2.]) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 + C1 +Subject To + R0: - C0 + C2 <= 0 + R1: - C1 + C3 <= 0 + R2: - C0 - C2 <= 0 + R3: - C1 - C3 <= 0 +Bounds + C0 free + C1 free + C2 free + C3 free +End +---------------------------------------- +GUROBI +Minimize + 0 x[0] + 0 x[1] + norm1_1 + 3 Constant +Subject To +Bounds + x[0] free + x[1] free + Constant = 1 +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x[0] , x[1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_11__0.txt b/tests/snapshots/all__lp_genexpr_norm1_11__0.txt new file mode 100644 index 0000000..be91ea1 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_11__0.txt @@ -0,0 +1,36 @@ +CVXPY +Maximize + Sum(x @ [ 1. -2.], None, False) +Subject To + 40: norm1(x) <= 1.0 +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + - C0 + 2 C1 +Subject To + R0: C0 - C2 <= 0 + R1: C1 - C3 <= 0 + R2: - C0 - C2 <= 0 + R3: - C1 - C3 <= 0 + R4: C2 + C3 <= 1 +Bounds + C0 free + C1 free + C2 free + C3 free +End +---------------------------------------- +GUROBI +Maximize + x[0] - 2 x[1] +Subject To + 40: norm1_1 <= 1 +Bounds + x[0] free + x[1] free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x[0] , x[1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_12__0.txt b/tests/snapshots/all__lp_genexpr_norm1_12__0.txt new file mode 100644 index 0000000..1329f07 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_12__0.txt @@ -0,0 +1,43 @@ +CVXPY +Minimize + norm1(X) +Subject To +Bounds + X free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 + C1 + C2 + C3 +Subject To + R0: - C0 + C4 <= 0 + R1: - C1 + C5 <= 0 + R2: - C2 + C6 <= 0 + R3: - C3 + C7 <= 0 + R4: - C0 - C4 <= 0 + R5: - C1 - C5 <= 0 + R6: - C2 - C6 <= 0 + R7: - C3 - C7 <= 0 +Bounds + C0 free + C1 free + C2 free + C3 free + C4 free + C5 free + C6 free + C7 free +End +---------------------------------------- +GUROBI +Minimize + 0 X[0,0] + 0 X[0,1] + 0 X[1,0] + 0 X[1,1] + norm1_1 +Subject To +Bounds + X[0,0] free + X[0,1] free + X[1,0] free + X[1,1] free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( X[0,0] , X[0,1] , X[1,0] , X[1,1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_13__0.txt b/tests/snapshots/all__lp_genexpr_norm1_13__0.txt new file mode 100644 index 0000000..e65bc5e --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_13__0.txt @@ -0,0 +1,53 @@ +CVXPY +Minimize + norm1(X + -[[1.00 -2.00] + [3.00 -4.00]]) +Subject To +Bounds + X free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 + C1 + C2 + C3 +Subject To + R0: - C0 + C4 <= 1 + R1: - C1 + C5 <= 3 + R2: - C2 + C6 <= -2 + R3: - C3 + C7 <= -4 + R4: - C0 - C4 <= -1 + R5: - C1 - C5 <= -3 + R6: - C2 - C6 <= 2 + R7: - C3 - C7 <= 4 +Bounds + C0 free + C1 free + C2 free + C3 free + C4 free + C5 free + C6 free + C7 free +End +---------------------------------------- +GUROBI +Minimize + norm1_2 +Subject To + R0: - X[0,0] + AddExpression_1[0,0] = -1 + R1: - X[0,1] + AddExpression_1[0,1] = 2 + R2: - X[1,0] + AddExpression_1[1,0] = -3 + R3: - X[1,1] + AddExpression_1[1,1] = 4 +Bounds + X[0,0] free + X[0,1] free + X[1,0] free + X[1,1] free + AddExpression_1[0,0] free + AddExpression_1[0,1] free + AddExpression_1[1,0] free + AddExpression_1[1,1] free +General Constraints + GC0: norm1_2 = NORM ( 1 ) ( AddExpression_1[0,0] , AddExpression_1[0,1] , + AddExpression_1[1,0] , AddExpression_1[1,1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_14__0.txt b/tests/snapshots/all__lp_genexpr_norm1_14__0.txt new file mode 100644 index 0000000..f8d7bec --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_14__0.txt @@ -0,0 +1,45 @@ +CVXPY +Minimize + norm1(X) + norm1([[1.00 -2.00] + [3.00 -4.00]]) +Subject To +Bounds + X free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 + C1 + C2 + C3 +Subject To + R0: - C0 + C4 <= 0 + R1: - C1 + C5 <= 0 + R2: - C2 + C6 <= 0 + R3: - C3 + C7 <= 0 + R4: - C0 - C4 <= 0 + R5: - C1 - C5 <= 0 + R6: - C2 - C6 <= 0 + R7: - C3 - C7 <= 0 +Bounds + C0 free + C1 free + C2 free + C3 free + C4 free + C5 free + C6 free + C7 free +End +---------------------------------------- +GUROBI +Minimize + 0 X[0,0] + 0 X[0,1] + 0 X[1,0] + 0 X[1,1] + norm1_1 + 10 Constant +Subject To +Bounds + X[0,0] free + X[0,1] free + X[1,0] free + X[1,1] free + Constant = 1 +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( X[0,0] , X[0,1] , X[1,0] , X[1,1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_15__0.txt b/tests/snapshots/all__lp_genexpr_norm1_15__0.txt new file mode 100644 index 0000000..958e053 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_15__0.txt @@ -0,0 +1,47 @@ +CVXPY +Maximize + Sum(X @ [[1.00 -2.00] + [3.00 -4.00]], None, False) +Subject To + 55: norm1(X) <= 1.0 +Bounds + X free +End +---------------------------------------- +AFTER COMPILATION +Minimize + - C0 - 3 C1 + 2 C2 + 4 C3 +Subject To + R0: C0 - C4 <= 0 + R1: C1 - C5 <= 0 + R2: C2 - C6 <= 0 + R3: C3 - C7 <= 0 + R4: - C0 - C4 <= 0 + R5: - C1 - C5 <= 0 + R6: - C2 - C6 <= 0 + R7: - C3 - C7 <= 0 + R8: C4 + C5 + C6 + C7 <= 1 +Bounds + C0 free + C1 free + C2 free + C3 free + C4 free + C5 free + C6 free + C7 free +End +---------------------------------------- +GUROBI +Maximize + X[0,0] - 2 X[0,1] + 3 X[1,0] - 4 X[1,1] +Subject To + 55: norm1_1 <= 1 +Bounds + X[0,0] free + X[0,1] free + X[1,0] free + X[1,1] free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( X[0,0] , X[0,1] , X[1,0] , X[1,1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_1__0.txt b/tests/snapshots/all__lp_genexpr_norm1_1__0.txt new file mode 100644 index 0000000..0e68ff6 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_1__0.txt @@ -0,0 +1,30 @@ +CVXPY +Minimize + norm1(x + -1.0) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 +Subject To + R0: - C0 + C1 <= 1 + R1: - C0 - C1 <= -1 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Minimize + norm1_2 +Subject To + R0: - x + AddExpression_1 = -1 +Bounds + x free + AddExpression_1 free +General Constraints + GC0: norm1_2 = NORM ( 1 ) ( AddExpression_1 ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_2__0.txt b/tests/snapshots/all__lp_genexpr_norm1_2__0.txt new file mode 100644 index 0000000..fd86060 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_2__0.txt @@ -0,0 +1,29 @@ +CVXPY +Minimize + norm1(x) + norm1(-1.0) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 +Subject To + R0: - C0 + C1 <= 0 + R1: - C0 - C1 <= 0 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Minimize + 0 x + norm1_1 + Constant +Subject To +Bounds + x free + Constant = 1 +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_3__0.txt b/tests/snapshots/all__lp_genexpr_norm1_3__0.txt new file mode 100644 index 0000000..1d314da --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_3__0.txt @@ -0,0 +1,31 @@ +CVXPY +Maximize + x +Subject To + 12: norm1(x) <= 1.0 +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + - C0 +Subject To + R0: C0 - C1 <= 0 + R1: - C0 - C1 <= 0 + R2: C1 <= 1 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Maximize + x +Subject To + 12: norm1_1 <= 1 +Bounds + x free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_4__0.txt b/tests/snapshots/all__lp_genexpr_norm1_4__0.txt new file mode 100644 index 0000000..931880e --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_4__0.txt @@ -0,0 +1,28 @@ +CVXPY +Minimize + norm1(x) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 +Subject To + R0: - C0 + C1 <= 0 + R1: - C0 - C1 <= 0 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Minimize + 0 x[0] + norm1_1 +Subject To +Bounds + x[0] free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x[0] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_5__0.txt b/tests/snapshots/all__lp_genexpr_norm1_5__0.txt new file mode 100644 index 0000000..2c2fed5 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_5__0.txt @@ -0,0 +1,30 @@ +CVXPY +Minimize + norm1(x + -1.0) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 +Subject To + R0: - C0 + C1 <= 1 + R1: - C0 - C1 <= -1 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Minimize + norm1_2 +Subject To + R0: - x[0] + AddExpression_1 = -1 +Bounds + x[0] free + AddExpression_1 free +General Constraints + GC0: norm1_2 = NORM ( 1 ) ( AddExpression_1 ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_6__0.txt b/tests/snapshots/all__lp_genexpr_norm1_6__0.txt new file mode 100644 index 0000000..94a5125 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_6__0.txt @@ -0,0 +1,29 @@ +CVXPY +Minimize + norm1(x) + norm1(-1.0) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 +Subject To + R0: - C0 + C1 <= 0 + R1: - C0 - C1 <= 0 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Minimize + 0 x[0] + norm1_1 + Constant +Subject To +Bounds + x[0] free + Constant = 1 +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x[0] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_7__0.txt b/tests/snapshots/all__lp_genexpr_norm1_7__0.txt new file mode 100644 index 0000000..026360f --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_7__0.txt @@ -0,0 +1,31 @@ +CVXPY +Maximize + x +Subject To + 25: norm1(x) <= 1.0 +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + - C0 +Subject To + R0: C0 - C1 <= 0 + R1: - C0 - C1 <= 0 + R2: C1 <= 1 +Bounds + C0 free + C1 free +End +---------------------------------------- +GUROBI +Maximize + x[0] +Subject To + 25: norm1_1 <= 1 +Bounds + x[0] free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x[0] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_8__0.txt b/tests/snapshots/all__lp_genexpr_norm1_8__0.txt new file mode 100644 index 0000000..bf23d9c --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_8__0.txt @@ -0,0 +1,33 @@ +CVXPY +Minimize + norm1(x) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 + C1 +Subject To + R0: - C0 + C2 <= 0 + R1: - C1 + C3 <= 0 + R2: - C0 - C2 <= 0 + R3: - C1 - C3 <= 0 +Bounds + C0 free + C1 free + C2 free + C3 free +End +---------------------------------------- +GUROBI +Minimize + 0 x[0] + 0 x[1] + norm1_1 +Subject To +Bounds + x[0] free + x[1] free +General Constraints + GC0: norm1_1 = NORM ( 1 ) ( x[0] , x[1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm1_9__0.txt b/tests/snapshots/all__lp_genexpr_norm1_9__0.txt new file mode 100644 index 0000000..219ace5 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm1_9__0.txt @@ -0,0 +1,37 @@ +CVXPY +Minimize + norm1(x + -[ 1. -2.]) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + C0 + C1 +Subject To + R0: - C0 + C2 <= 1 + R1: - C1 + C3 <= -2 + R2: - C0 - C2 <= -1 + R3: - C1 - C3 <= 2 +Bounds + C0 free + C1 free + C2 free + C3 free +End +---------------------------------------- +GUROBI +Minimize + norm1_2 +Subject To + R0: - x[0] + AddExpression_1[0] = -1 + R1: - x[1] + AddExpression_1[1] = 2 +Bounds + x[0] free + x[1] free + AddExpression_1[0] free + AddExpression_1[1] free +General Constraints + GC0: norm1_2 = NORM ( 1 ) ( AddExpression_1[0] , AddExpression_1[1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm2_0__0.txt b/tests/snapshots/all__lp_genexpr_norm2_0__0.txt new file mode 100644 index 0000000..bf4ac76 --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm2_0__0.txt @@ -0,0 +1,34 @@ +CVXPY +Minimize + Pnorm(x, 2) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + x_0 +Subject To + R0: - x_0 + soc_t_0 = 0 + R1: - x_1 + soc_x_1 = 0 + R2: - x_2 + soc_x_2 = 0 + qc0: [ - soc_t_0 ^2 + soc_x_1 ^2 + soc_x_2 ^2 ] <= 0 +Bounds + x_0 free + x_1 free + x_2 free + soc_x_1 free + soc_x_2 free +End +---------------------------------------- +GUROBI +Minimize + 0 x[0] + 0 x[1] + norm2_1 +Subject To +Bounds + x[0] free + x[1] free +General Constraints + GC0: norm2_1 = NORM ( 2 ) ( x[0] , x[1] ) +End \ No newline at end of file diff --git a/tests/snapshots/all__lp_genexpr_norm2_1__0.txt b/tests/snapshots/all__lp_genexpr_norm2_1__0.txt new file mode 100644 index 0000000..dae372e --- /dev/null +++ b/tests/snapshots/all__lp_genexpr_norm2_1__0.txt @@ -0,0 +1,38 @@ +CVXPY +Minimize + Pnorm(x + Promote(-1.0, (2,)), 2) +Subject To +Bounds + x free +End +---------------------------------------- +AFTER COMPILATION +Minimize + x_0 +Subject To + R0: - x_0 + soc_t_0 = 0 + R1: - x_1 + soc_x_1 = -1 + R2: - x_2 + soc_x_2 = -1 + qc0: [ - soc_t_0 ^2 + soc_x_1 ^2 + soc_x_2 ^2 ] <= 0 +Bounds + x_0 free + x_1 free + x_2 free + soc_x_1 free + soc_x_2 free +End +---------------------------------------- +GUROBI +Minimize + norm2_2 +Subject To + R0: - x[0] + AddExpression_1[0] = -1 + R1: - x[1] + AddExpression_1[1] = -1 +Bounds + x[0] free + x[1] free + AddExpression_1[0] free + AddExpression_1[1] free +General Constraints + GC0: norm2_2 = NORM ( 2 ) ( AddExpression_1[0] , AddExpression_1[1] ) +End \ No newline at end of file diff --git a/tests/test_problems.py b/tests/test_problems.py index b7789e9..cba5936 100644 --- a/tests/test_problems.py +++ b/tests/test_problems.py @@ -45,6 +45,7 @@ def all_problems() -> Iterator[ProblemTestCase]: genexpr_abs, genexpr_min_max, genexpr_minimum_maximum, + genexpr_norm1, indexing, attributes, invalid_expressions, @@ -343,6 +344,35 @@ def genexpr_minimum_maximum() -> Iterator[cp.Problem]: yield cp.Problem(cp.Maximize(cp.sum(x)), [cp.maximum(A, B) <= 4, x == 1]) +@group_cases("genexpr_norm1") +def genexpr_norm1() -> Iterator[cp.Problem]: + x = cp.Variable(name="x") + yield cp.Problem(cp.Minimize(cp.norm1(x))) + yield cp.Problem(cp.Minimize(cp.norm1(x - 1))) + yield cp.Problem(cp.Minimize(cp.norm1(x) + cp.norm1(-1))) + yield cp.Problem(cp.Maximize(x), [cp.norm1(x) <= 1]) + + x = cp.Variable(1, name="x") + yield cp.Problem(cp.Minimize(cp.norm1(x))) + yield cp.Problem(cp.Minimize(cp.norm1(x - 1))) + yield cp.Problem(cp.Minimize(cp.norm1(x) + cp.norm1(-1))) + yield cp.Problem(cp.Maximize(x), [cp.norm1(x) <= 1]) + + x = cp.Variable(2, name="x") + A = np.array([1, -2]) + yield cp.Problem(cp.Minimize(cp.norm1(x))) + yield cp.Problem(cp.Minimize(cp.norm1(x - A))) + yield cp.Problem(cp.Minimize(cp.norm1(x) + cp.norm1(A))) + yield cp.Problem(cp.Maximize(cp.sum(cp.multiply(x, A))), [cp.norm1(x) <= 1]) + + x = cp.Variable((2, 2), name="X") + A = np.array([[1, -2], [3, -4]]) + yield cp.Problem(cp.Minimize(cp.norm1(x))) + yield cp.Problem(cp.Minimize(cp.norm1(x - A))) + yield cp.Problem(cp.Minimize(cp.norm1(x) + cp.norm1(A))) + yield cp.Problem(cp.Maximize(cp.sum(cp.multiply(x, A))), [cp.norm1(x) <= 1]) + + @group_cases("indexing") def indexing() -> Iterator[cp.Problem]: x = cp.Variable(2, name="x", nonneg=True)