Beispiel #1
0
 def test_acos(self):
     m = pe.Block(concrete=True)
     m.x = pe.Var()
     m.c = pe.Constraint(expr=pe.inequality(body=pe.acos(m.x), lower=1, upper=2))
     fbbt(m)
     self.assertAlmostEqual(pe.value(m.x.lb), math.cos(2))
     self.assertAlmostEqual(pe.value(m.x.ub), math.cos(1))
Beispiel #2
0
 def test_atan(self):
     m = pe.Block(concrete=True)
     m.x = pe.Var()
     m.c = pe.Constraint(expr=pe.inequality(body=pe.atan(m.x), lower=-0.5, upper=0.5))
     fbbt(m)
     self.assertAlmostEqual(pe.value(m.x.lb), math.tan(-0.5))
     self.assertAlmostEqual(pe.value(m.x.ub), math.tan(0.5))
Beispiel #3
0
 def test_always_feasible(self):
     m = pe.ConcreteModel()
     m.x = pe.Var(bounds=(1,2))
     m.y = pe.Var(bounds=(1,2))
     m.c = pe.Constraint(expr=m.x + m.y >= 0)
     fbbt(m)
     self.assertTrue(m.c.active)
     fbbt(m, deactivate_satisfied_constraints=True)
     self.assertFalse(m.c.active)
Beispiel #4
0
    def test_pow5(self):
        m = pe.ConcreteModel()
        m.x = pe.Var()
        m.y = pe.Var(bounds=(0.5, 1))
        m.c = pe.Constraint(expr=2**m.x == m.y)

        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -1)
        self.assertAlmostEqual(m.x.ub, 0)
Beispiel #5
0
    def test_cos(self):
        m = pe.Block(concrete=True)
        m.x = pe.Var(bounds=(0, math.pi))
        m.c = pe.Constraint(expr=pe.inequality(body=pe.cos(m.x), lower=-0.5, upper=0.5))
        fbbt(m)
        self.assertAlmostEqual(pe.value(m.x.lb), math.acos(0.5))
        self.assertAlmostEqual(pe.value(m.x.ub), math.acos(-0.5))

        m = pe.Block(concrete=True)
        m.x = pe.Var()
        m.c = pe.Constraint(expr=pe.inequality(body=pe.cos(m.x), lower=-0.5, upper=0.5))
        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)
Beispiel #6
0
 def test_add(self):
     x_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8), (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     c_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8), (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     for xl, xu in x_bounds:
         for cl, cu in c_bounds:
             m = pe.Block(concrete=True)
             m.x = pe.Var(bounds=(xl, xu))
             m.y = pe.Var()
             m.p = pe.Param(mutable=True)
             m.p.value = 1
             m.c = pe.Constraint(expr=pe.inequality(body=m.x+m.y+(m.p+1), lower=cl, upper=cu))
             new_bounds = fbbt(m)
             self.assertEqual(new_bounds[m.x], (pe.value(m.x.lb), pe.value(m.x.ub)))
             self.assertEqual(new_bounds[m.y], (pe.value(m.y.lb), pe.value(m.y.ub)))
             x = np.linspace(pe.value(m.x.lb), pe.value(m.x.ub), 100)
             z = np.linspace(pe.value(m.c.lower), pe.value(m.c.upper), 100)
             if m.y.lb is None:
                 yl = -np.inf
             else:
                 yl = m.y.lb
             if m.y.ub is None:
                 yu = np.inf
             else:
                 yu = m.y.ub
             for _x in x:
                 _y = z - _x - m.p.value - 1
                 self.assertTrue(np.all(yl <= _y))
                 self.assertTrue(np.all(yu >= _y))
Beispiel #7
0
 def test_multiple_constraints2(self):
     m = pe.ConcreteModel()
     m.x = pe.Var(bounds=(-3, 3))
     m.y = pe.Var(bounds=(None, 0))
     m.z = pe.Var()
     m.c = pe.ConstraintList()
     m.c.add(-m.x - m.y >= -1)
     m.c.add(-m.x - m.y <= -1)
     m.c.add(-m.y - m.x*m.z >= -2)
     m.c.add(-m.y - m.x*m.z <= 2)
     m.c.add(-m.x - m.z == 1)
     fbbt(m)
     self.assertAlmostEqual(pe.value(m.x.lb), 1, 8)
     self.assertAlmostEqual(pe.value(m.x.ub), 1, 8)
     self.assertAlmostEqual(pe.value(m.y.lb), 0, 8)
     self.assertAlmostEqual(pe.value(m.y.ub), 0, 8)
     self.assertAlmostEqual(pe.value(m.z.lb), -2, 8)
     self.assertAlmostEqual(pe.value(m.z.ub), -2, 8)
Beispiel #8
0
 def test_log(self):
     c_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8), (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     for cl, cu in c_bounds:
         m = pe.Block(concrete=True)
         m.x = pe.Var()
         m.c = pe.Constraint(expr=pe.inequality(body=pe.log(m.x), lower=cl, upper=cu))
         fbbt(m)
         z = np.linspace(pe.value(m.c.lower), pe.value(m.c.upper), 100)
         if m.x.lb is None:
             xl = -np.inf
         else:
             xl = pe.value(m.x.lb)
         if m.x.ub is None:
             xu = np.inf
         else:
             xu = pe.value(m.x.ub)
         x = np.exp(z)
         self.assertTrue(np.all(xl <= x))
         self.assertTrue(np.all(xu >= x))
Beispiel #9
0
    def test_x_cubed(self):
        m = pe.ConcreteModel()
        m.x = pe.Var()
        m.y = pe.Var()
        m.c = pe.Constraint(expr=m.x**3 == m.y)

        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)
        self.assertEqual(m.y.lb, None)
        self.assertEqual(m.y.ub, None)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(1)
        m.y.setub(8)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(-8)
        m.y.setub(8)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(-5)
        m.y.setub(8)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -5.0**(1.0/3.0))
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(-8)
        m.y.setub(-1)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, -1)
Beispiel #10
0
    def test_sqrt(self):
        m = pe.ConcreteModel()
        m.x = pe.Var()
        m.y = pe.Var()
        m.c = pe.Constraint(expr=pe.sqrt(m.x) == m.y)

        fbbt(m)
        self.assertEqual(m.x.lb, 0)
        self.assertEqual(m.x.ub, None)
        self.assertEqual(m.y.lb, 0)
        self.assertEqual(m.y.ub, None)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(-5)
        m.y.setub(-1)
        with self.assertRaises(InfeasibleConstraintException):
            fbbt(m)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(0)
        m.y.setlb(None)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 0)
        self.assertAlmostEqual(m.x.ub, 0)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(2)
        m.y.setlb(1)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 4)

        m.x.setlb(None)
        m.x.setub(0)
        m.y.setlb(None)
        m.y.setub(None)
        fbbt(m)
        self.assertAlmostEqual(m.y.lb, 0)
        self.assertAlmostEqual(m.y.ub, 0)
Beispiel #11
0
    def test_binary(self):
        m = pe.ConcreteModel()
        m.x = pe.Var(domain=pe.Binary)
        m.y = pe.Var(domain=pe.Binary)
        m.c = pe.Constraint(expr=m.x + m.y >= 1.5)
        fbbt(m)
        self.assertEqual(pe.value(m.x.lb), 1)
        self.assertEqual(pe.value(m.x.ub), 1)
        self.assertEqual(pe.value(m.y.lb), 1)
        self.assertEqual(pe.value(m.y.ub), 1)

        m = pe.ConcreteModel()
        m.x = pe.Var(domain=pe.Binary)
        m.y = pe.Var(domain=pe.Binary)
        m.c = pe.Constraint(expr=m.x + m.y <= 0.5)
        fbbt(m)
        self.assertEqual(pe.value(m.x.lb), 0)
        self.assertEqual(pe.value(m.x.ub), 0)
        self.assertEqual(pe.value(m.y.lb), 0)
        self.assertEqual(pe.value(m.y.ub), 0)
Beispiel #12
0
 def test_pow4(self):
     y_bounds = [(0.5, 2.8), (0, 2.8), (1, 2.8), (0.5, 1), (0, 0.5)]
     exp_vals = [-3, -2.5, -2, -1.5, -1, -0.5, 0.5, 1, 1.5, 2, 2.5, 3]
     for yl, yu in y_bounds:
         for _exp_val in exp_vals:
             m = pe.Block(concrete=True)
             m.x = pe.Var()
             m.y = pe.Var(bounds=(yl, yu))
             m.c = pe.Constraint(expr=m.x**_exp_val == m.y)
             fbbt(m)
             y = np.linspace(pe.value(m.y.lb) + 1e-6, pe.value(m.y.ub), 100, endpoint=True)
             if m.x.lb is None:
                 xl = -np.inf
             else:
                 xl = m.x.lb
             if m.x.ub is None:
                 xu = np.inf
             else:
                 xu = m.x.ub
             _x = np.exp(np.log(y) / _exp_val)
             self.assertTrue(np.all(xl <= _x))
             self.assertTrue(np.all(xu >= _x))
Beispiel #13
0
    def test_x_pow_minus_3(self):
        m = pe.ConcreteModel()
        m.x = pe.Var()
        m.y = pe.Var()
        m.c = pe.Constraint(expr=m.x**(-3) == m.y)

        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)
        self.assertEqual(m.y.lb, None)
        self.assertEqual(m.y.ub, None)

        m.y.setlb(-1)
        m.y.setub(-0.125)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, -1)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(0)
        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertAlmostEqual(m.x.ub, -1)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(-1)
        m.y.setlb(1)
        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)

        m.y.setlb(0.125)
        m.y.setub(1)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 2)
Beispiel #14
0
    def test_x_pow_minus_3(self):
        m = pyo.ConcreteModel()
        m.x = pyo.Var()
        m.y = pyo.Var()
        m.c = pyo.Constraint(expr=m.x**(-3) == m.y)

        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)
        self.assertEqual(m.y.lb, None)
        self.assertEqual(m.y.ub, None)

        m.y.setlb(-1)
        m.y.setub(-0.125)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, -1)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(0)
        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertAlmostEqual(m.x.ub, -1)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(-1)
        m.y.setub(1)
        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)

        m.y.setlb(0.125)
        m.y.setub(1)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 2)
Beispiel #15
0
 def test_log10(self):
     c_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8),
                 (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     for cl, cu in c_bounds:
         m = pyo.Block(concrete=True)
         m.x = pyo.Var()
         m.c = pyo.Constraint(
             expr=pyo.inequality(body=pyo.log10(m.x), lower=cl, upper=cu))
         fbbt(m)
         z = np.linspace(pyo.value(m.c.lower), pyo.value(m.c.upper), 100)
         if m.x.lb is None:
             xl = -np.inf
         else:
             xl = pyo.value(m.x.lb)
         if m.x.ub is None:
             xu = np.inf
         else:
             xu = pyo.value(m.x.ub)
         x = 10**z
         print(xl, xu, cl, cu)
         print(x)
         self.assertTrue(np.all(xl <= x))
         self.assertTrue(np.all(xu >= x))
Beispiel #16
0
 def test_no_update_bounds(self):
     m = pe.ConcreteModel()
     m.x = pe.Var(bounds=(0, 1))
     m.y = pe.Var(bounds=(1, 1))
     m.c = pe.Constraint(expr=m.x + m.y == 1)
     new_bounds = fbbt(m, update_variable_bounds=False)
     self.assertEqual(pe.value(m.x.lb), 0)
     self.assertEqual(pe.value(m.x.ub), 1)
     self.assertEqual(pe.value(m.y.lb), 1)
     self.assertEqual(pe.value(m.y.ub), 1)
     self.assertAlmostEqual(new_bounds[m.x][0], 0, 12)
     self.assertAlmostEqual(new_bounds[m.x][1], 0, 12)
     self.assertAlmostEqual(new_bounds[m.y][0], 1, 12)
     self.assertAlmostEqual(new_bounds[m.y][1], 1, 12)
Beispiel #17
0
 def test_exp(self):
     c_bounds = [(-2.5, 2.8), (0.5, 2.8), (0, 2.8), (1, 2.8), (0.5, 1)]
     for cl, cu in c_bounds:
         m = pe.Block(concrete=True)
         m.x = pe.Var()
         m.c = pe.Constraint(expr=pe.inequality(body=pe.exp(m.x), lower=cl, upper=cu))
         fbbt(m)
         if pe.value(m.c.lower) <= 0:
             _cl = 1e-6
         else:
             _cl = pe.value(m.c.lower)
         z = np.linspace(_cl, pe.value(m.c.upper), 100)
         if m.x.lb is None:
             xl = -np.inf
         else:
             xl = pe.value(m.x.lb)
         if m.x.ub is None:
             xu = np.inf
         else:
             xu = pe.value(m.x.ub)
         x = np.log(z)
         self.assertTrue(np.all(xl <= x))
         self.assertTrue(np.all(xu >= x))
Beispiel #18
0
 def test_pow1(self):
     x_bounds = [(0, 2.8), (0.5, 2.8), (1, 2.8), (0.5, 1)]
     c_bounds = [(-2.5, 2.8), (0.5, 2.8), (-2.5, 0), (0, 2.8), (1, 2.8), (0.5, 1)]
     for xl, xu in x_bounds:
         for cl, cu in c_bounds:
             m = pe.Block(concrete=True)
             m.x = pe.Var(bounds=(xl, xu))
             m.y = pe.Var()
             m.c = pe.Constraint(expr=pe.inequality(body=m.x**m.y, lower=cl, upper=cu))
             fbbt(m)
             x = np.linspace(pe.value(m.x.lb) + 1e-6, pe.value(m.x.ub), 100, endpoint=False)
             z = np.linspace(pe.value(m.c.lower) + 1e-6, pe.value(m.c.upper), 100, endpoint=False)
             if m.y.lb is None:
                 yl = -np.inf
             else:
                 yl = m.y.lb
             if m.y.ub is None:
                 yu = np.inf
             else:
                 yu = m.y.ub
             for _x in x:
                 _y = np.log(abs(z)) / np.log(abs(_x))
                 self.assertTrue(np.all(yl <= _y))
                 self.assertTrue(np.all(yu >= _y))
Beispiel #19
0
 def test_sub1(self):
     x_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8), (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     c_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8), (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     for xl, xu in x_bounds:
         for cl, cu in c_bounds:
             m = pe.Block(concrete=True)
             m.x = pe.Var(bounds=(xl, xu))
             m.y = pe.Var()
             m.c = pe.Constraint(expr=pe.inequality(body=m.x-m.y, lower=cl, upper=cu))
             fbbt(m)
             x = np.linspace(pe.value(m.x.lb), pe.value(m.x.ub), 100)
             z = np.linspace(pe.value(m.c.lower), pe.value(m.c.upper), 100)
             if m.y.lb is None:
                 yl = -np.inf
             else:
                 yl = m.y.lb
             if m.y.ub is None:
                 yu = np.inf
             else:
                 yu = m.y.ub
             for _x in x:
                 _y = _x - z
                 self.assertTrue(np.all(yl <= _y))
                 self.assertTrue(np.all(yu >= _y))
Beispiel #20
0
 def test_pow2(self):
     x_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8),
                 (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     c_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8),
                 (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     for xl, xu in x_bounds:
         for cl, cu in c_bounds:
             m = pe.Block(concrete=True)
             m.x = pe.Var(bounds=(xl, xu))
             m.y = pe.Var()
             m.c = pe.Constraint(
                 expr=pe.inequality(body=m.y**m.x, lower=cl, upper=cu))
             fbbt(m)
             x = np.linspace(pe.value(m.x.lb) + 1e-6,
                             pe.value(m.x.ub),
                             100,
                             endpoint=False)
             z = np.linspace(pe.value(m.c.lower) + 1e-6,
                             pe.value(m.c.upper),
                             100,
                             endpoint=False)
             if m.y.lb is None:
                 yl = -np.inf
             else:
                 yl = m.y.lb
             if m.y.ub is None:
                 yu = np.inf
             else:
                 yu = m.y.ub
             for _x in x:
                 _y = np.exp(np.log(abs(z)) / _x)
                 self.assertTrue(np.all(yl <= _y))
                 self.assertTrue(np.all(yu >= _y))
                 _y = -_y
                 self.assertTrue(np.all(yl <= _y))
                 self.assertTrue(np.all(yu >= _y))
Beispiel #21
0
 def test_sub2(self):
     x_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8), (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     c_bounds = [(-2.5, 2.8), (-2.5, -0.5), (0.5, 2.8), (-2.5, 0), (0, 2.8), (-2.5, -1), (1, 2.8), (-1, -0.5), (0.5, 1)]
     for xl, xu in x_bounds:
         for cl, cu in c_bounds:
             m = pe.Block(concrete=True)
             m.x = pe.Var(bounds=(xl, xu))
             m.y = pe.Var()
             m.c = pe.Constraint(expr=pe.inequality(body=m.y-m.x, lower=cl, upper=cu))
             fbbt(m)
             x = np.linspace(pe.value(m.x.lb), pe.value(m.x.ub), 100)
             z = np.linspace(pe.value(m.c.lower), pe.value(m.c.upper), 100)
             if m.y.lb is None:
                 yl = -np.inf
             else:
                 yl = m.y.lb
             if m.y.ub is None:
                 yu = np.inf
             else:
                 yu = m.y.ub
             for _x in x:
                 _y = z + _x
                 self.assertTrue(np.all(yl <= _y))
                 self.assertTrue(np.all(yu >= _y))
Beispiel #22
0
 def test_pow1(self):
     x_bounds = [(0, 2.8), (0.5, 2.8), (1, 2.8), (0.5, 1)]
     c_bounds = [(-2.5, 2.8), (0.5, 2.8), (-2.5, 0), (0, 2.8), (1, 2.8),
                 (0.5, 1)]
     for xl, xu in x_bounds:
         for cl, cu in c_bounds:
             m = pyo.Block(concrete=True)
             m.x = pyo.Var(bounds=(xl, xu))
             m.y = pyo.Var()
             m.c = pyo.Constraint(
                 expr=pyo.inequality(body=m.x**m.y, lower=cl, upper=cu))
             if xl > 0 and cu <= 0:
                 with self.assertRaises(InfeasibleConstraintException):
                     fbbt(m)
             else:
                 fbbt(m)
                 x = np.linspace(pyo.value(m.x.lb) + 1e-6,
                                 pyo.value(m.x.ub),
                                 100,
                                 endpoint=False)
                 z = np.linspace(pyo.value(m.c.lower) + 1e-6,
                                 pyo.value(m.c.upper),
                                 100,
                                 endpoint=False)
                 if m.y.lb is None:
                     yl = -np.inf
                 else:
                     yl = m.y.lb
                 if m.y.ub is None:
                     yu = np.inf
                 else:
                     yu = m.y.ub
                 for _x in x:
                     _y = np.log(abs(z)) / np.log(abs(_x))
                     self.assertTrue(np.all(yl <= _y))
                     self.assertTrue(np.all(yu >= _y))
Beispiel #23
0
    def test_skip_unknown_expression1(self):

        m = pyo.ConcreteModel()
        m.x = pyo.Var(bounds=(1, 1))
        m.y = pyo.Var()
        expr = DummyExpr([m.x, m.y])
        m.c = pyo.Constraint(expr=expr == 1)

        OUT = StringIO()
        with LoggingIntercept(OUT, 'pyomo.contrib.fbbt.fbbt'):
            new_bounds = fbbt(m)

        self.assertEqual(pyo.value(m.x.lb), 1)
        self.assertEqual(pyo.value(m.x.ub), 1)
        self.assertEqual(pyo.value(m.y.lb), None)
        self.assertEqual(pyo.value(m.y.ub), None)
        self.assertIn("Unsupported expression type for FBBT", OUT.getvalue())
Beispiel #24
0
    def test_skip_unknown_expression2(self):
        def dummy_unary_expr(x):
            return 0.5 * x

        m = pyo.ConcreteModel()
        m.x = pyo.Var(bounds=(0, 4))
        expr = UnaryFunctionExpression((m.x, ),
                                       name='dummy_unary_expr',
                                       fcn=dummy_unary_expr)
        m.c = pyo.Constraint(expr=expr == 1)

        OUT = StringIO()
        with LoggingIntercept(OUT, 'pyomo.contrib.fbbt.fbbt'):
            new_bounds = fbbt(m)

        self.assertEqual(pyo.value(m.x.lb), 0)
        self.assertEqual(pyo.value(m.x.ub), 4)
        self.assertIn("Unsupported expression type for FBBT", OUT.getvalue())
Beispiel #25
0
    def test_skip_unknown_expression2(self):
        def dummy_unary_expr(x):
            return 0.5*x

        m = pe.ConcreteModel()
        m.x = pe.Var(bounds=(0,4))
        expr = UnaryFunctionExpression((m.x,), name='dummy_unary_expr', fcn=dummy_unary_expr)
        m.c = pe.Constraint(expr=expr == 1)
        logging_io = io.StringIO()
        handler = logging.StreamHandler(stream=logging_io)
        handler.setLevel(logging.WARNING)
        logger = logging.getLogger('pyomo.contrib.fbbt.fbbt')
        logger.addHandler(handler)
        new_bounds = fbbt(m)
        handler.flush()
        self.assertEqual(pe.value(m.x.lb), 0)
        self.assertEqual(pe.value(m.x.ub), 4)
        a = "Unsupported expression type for FBBT"
        b = logging_io.getvalue()
        a = a.strip()
        b = b.strip()
        self.assertTrue(b.startswith(a))
        logger.removeHandler(handler)
Beispiel #26
0
    def test_skip_unknown_expression1(self):

        m = pe.ConcreteModel()
        m.x = pe.Var(bounds=(1,1))
        m.y = pe.Var()
        expr = DummyExpr([m.x, m.y])
        m.c = pe.Constraint(expr=expr == 1)
        logging_io = io.StringIO()
        handler = logging.StreamHandler(stream=logging_io)
        handler.setLevel(logging.WARNING)
        logger = logging.getLogger('pyomo.contrib.fbbt.fbbt')
        logger.addHandler(handler)
        new_bounds = fbbt(m)
        handler.flush()
        self.assertEqual(pe.value(m.x.lb), 1)
        self.assertEqual(pe.value(m.x.ub), 1)
        self.assertEqual(pe.value(m.y.lb), None)
        self.assertEqual(pe.value(m.y.ub), None)
        a = "Unsupported expression type for FBBT"
        b = logging_io.getvalue()
        a = a.strip()
        b = b.strip()
        self.assertTrue(b.startswith(a))
        logger.removeHandler(handler)
Beispiel #27
0
    def test_skip_unknown_expression1(self):

        m = pe.ConcreteModel()
        m.x = pe.Var(bounds=(1, 1))
        m.y = pe.Var()
        expr = DummyExpr([m.x, m.y])
        m.c = pe.Constraint(expr=expr == 1)
        logging_io = io.StringIO()
        handler = logging.StreamHandler(stream=logging_io)
        handler.setLevel(logging.WARNING)
        logger = logging.getLogger('pyomo.contrib.fbbt.fbbt')
        logger.addHandler(handler)
        new_bounds = fbbt(m)
        handler.flush()
        self.assertEqual(pe.value(m.x.lb), 1)
        self.assertEqual(pe.value(m.x.ub), 1)
        self.assertEqual(pe.value(m.y.lb), None)
        self.assertEqual(pe.value(m.y.ub), None)
        a = "Unsupported expression type for FBBT"
        b = logging_io.getvalue()
        a = a.strip()
        b = b.strip()
        self.assertTrue(b.startswith(a))
        logger.removeHandler(handler)
Beispiel #28
0
    def solve(self, model, **kwds):
        """Solve the model.

        Warning: this solver is still in beta. Keyword arguments subject to
        change. Undocumented keyword arguments definitely subject to change.

        Args:
            model (Block): a Pyomo model or block to be solved
        """
        config = self.CONFIG(kwds.pop('options', {}))
        config.set_value(kwds)

        solve_data = MindtPySolveData()
        solve_data.results = SolverResults()
        solve_data.timing = Bunch()
        solve_data.curr_int_sol = []
        solve_data.should_terminate = False
        solve_data.integer_list = []

        check_config(config)

        # if the objective function is a constant, dual bound constraint is not added.
        obj = next(model.component_data_objects(ctype=Objective, active=True))
        if obj.expr.polynomial_degree() == 0:
            config.use_dual_bound = False

        if config.use_fbbt:
            fbbt(model)
            # TODO: logging_level is not logging.INFO here
            config.logger.info(
                'Use the fbbt to tighten the bounds of variables')

        solve_data.original_model = model
        solve_data.working_model = model.clone()
        if config.integer_to_binary:
            TransformationFactory('contrib.integer_to_binary'). \
                apply_to(solve_data.working_model)

        new_logging_level = logging.INFO if config.tee else None
        with time_code(solve_data.timing, 'total', is_main_timer=True), \
                lower_logger_level_to(config.logger, new_logging_level), \
                create_utility_block(solve_data.working_model, 'MindtPy_utils', solve_data):
            config.logger.info('---Starting MindtPy---')

            MindtPy = solve_data.working_model.MindtPy_utils
            setup_results_object(solve_data, config)
            process_objective(
                solve_data,
                config,
                move_linear_objective=(config.init_strategy == 'FP' or
                                       config.add_regularization is not None),
                use_mcpp=config.use_mcpp,
                updata_var_con_list=config.add_regularization is None)
            # The epigraph constraint is very "flat" for branching rules,
            # we want to use to original model for the main mip.
            if MindtPy.objective_list[0].expr.polynomial_degree() in {
                    1, 0
            } and config.add_regularization is not None:
                MindtPy.objective_list[0].activate()
                MindtPy.objective_constr.deactivate()
                MindtPy.objective.deactivate()

            # Save model initial values.
            solve_data.initial_var_values = list(
                v.value for v in MindtPy.variable_list)

            # Store the initial model state as the best solution found. If we
            # find no better solution, then we will restore from this copy.
            solve_data.best_solution_found = None
            solve_data.best_solution_found_time = None

            # Record solver name
            solve_data.results.solver.name = 'MindtPy' + str(config.strategy)

            # Validate the model to ensure that MindtPy is able to solve it.
            if not model_is_valid(solve_data, config):
                return

            # Create a model block in which to store the generated feasibility
            # slack constraints. Do not leave the constraints on by default.
            feas = MindtPy.feas_opt = Block()
            feas.deactivate()
            feas.feas_constraints = ConstraintList(
                doc='Feasibility Problem Constraints')

            # Create a model block in which to store the generated linear
            # constraints. Do not leave the constraints on by default.
            lin = MindtPy.cuts = Block()
            lin.deactivate()

            # no-good cuts exclude particular discrete decisions
            lin.no_good_cuts = ConstraintList(doc='no-good cuts')
            # Feasible no-good cuts exclude discrete realizations that have
            # been explored via an NLP subproblem. Depending on model
            # characteristics, the user may wish to revisit NLP subproblems
            # (with a different initialization, for example). Therefore, these
            # cuts are not enabled by default.
            #
            # Note: these cuts will only exclude integer realizations that are
            # not already in the primary no_good_cuts ConstraintList.
            lin.feasible_no_good_cuts = ConstraintList(
                doc='explored no-good cuts')
            lin.feasible_no_good_cuts.deactivate()

            # Set up iteration counters
            solve_data.nlp_iter = 0
            solve_data.mip_iter = 0
            solve_data.mip_subiter = 0
            solve_data.nlp_infeasible_counter = 0
            if config.init_strategy == 'FP':
                solve_data.fp_iter = 1

            # set up bounds
            solve_data.LB = float('-inf')
            solve_data.UB = float('inf')
            solve_data.LB_progress = [solve_data.LB]
            solve_data.UB_progress = [solve_data.UB]
            if config.single_tree and (config.add_no_good_cuts
                                       or config.use_tabu_list):
                solve_data.stored_bound = {}
            if config.strategy == 'GOA' and (config.add_no_good_cuts
                                             or config.use_tabu_list):
                solve_data.num_no_good_cuts_added = {}

            # Set of NLP iterations for which cuts were generated
            lin.nlp_iters = Set(dimen=1)

            # Set of MIP iterations for which cuts were generated in ECP
            lin.mip_iters = Set(dimen=1)

            if config.feasibility_norm == 'L1' or config.feasibility_norm == 'L2':
                feas.nl_constraint_set = RangeSet(
                    len(MindtPy.nonlinear_constraint_list),
                    doc='Integer index set over the nonlinear constraints.')
                # Create slack variables for feasibility problem
                feas.slack_var = Var(feas.nl_constraint_set,
                                     domain=NonNegativeReals,
                                     initialize=1)
            else:
                feas.slack_var = Var(domain=NonNegativeReals, initialize=1)

            # Create slack variables for OA cuts
            if config.add_slack:
                lin.slack_vars = VarList(bounds=(0, config.max_slack),
                                         initialize=0,
                                         domain=NonNegativeReals)

            # Flag indicating whether the solution improved in the past
            # iteration or not
            solve_data.solution_improved = False
            solve_data.bound_improved = False

            if config.nlp_solver == 'ipopt':
                if not hasattr(solve_data.working_model, 'ipopt_zL_out'):
                    solve_data.working_model.ipopt_zL_out = Suffix(
                        direction=Suffix.IMPORT)
                if not hasattr(solve_data.working_model, 'ipopt_zU_out'):
                    solve_data.working_model.ipopt_zU_out = Suffix(
                        direction=Suffix.IMPORT)

            # Initialize the main problem
            with time_code(solve_data.timing, 'initialization'):
                MindtPy_initialize_main(solve_data, config)

            # Algorithm main loop
            with time_code(solve_data.timing, 'main loop'):
                MindtPy_iteration_loop(solve_data, config)
            if solve_data.best_solution_found is not None:
                # Update values in original model
                copy_var_list_values(from_list=solve_data.best_solution_found.
                                     MindtPy_utils.variable_list,
                                     to_list=MindtPy.variable_list,
                                     config=config)
                copy_var_list_values(MindtPy.variable_list, [
                    i
                    for i in solve_data.original_model.component_data_objects(
                        Var) if not i.fixed
                ], config)
                # exclude fixed variables here. This is consistent with the definition of variable_list in GDPopt.util

            solve_data.results.problem.lower_bound = solve_data.LB
            solve_data.results.problem.upper_bound = solve_data.UB

        solve_data.results.solver.timing = solve_data.timing
        solve_data.results.solver.user_time = solve_data.timing.total
        solve_data.results.solver.wallclock_time = solve_data.timing.total
        solve_data.results.solver.iterations = solve_data.mip_iter
        solve_data.results.solver.num_infeasible_nlp_subproblem = solve_data.nlp_infeasible_counter
        solve_data.results.solver.best_solution_found_time = solve_data.best_solution_found_time

        if config.single_tree:
            solve_data.results.solver.num_nodes = solve_data.nlp_iter - \
                (1 if config.init_strategy == 'rNLP' else 0)

        return solve_data.results
Beispiel #29
0
    def test_x_pow_minus_2(self):
        m = pyo.ConcreteModel()
        m.x = pyo.Var()
        m.y = pyo.Var()
        m.c = pyo.Constraint(expr=m.x**(-2) == m.y)

        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)
        self.assertEqual(m.y.lb, 0)
        self.assertEqual(m.y.ub, None)

        m.y.setlb(-5)
        m.y.setub(-1)
        with self.assertRaises(InfeasibleConstraintException):
            fbbt(m)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(0)
        with self.assertRaises(InfeasibleConstraintException):
            fbbt(m)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(1)
        m.y.setlb(0.25)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(0)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(None)
        m.x.setub(0)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, -1)
Beispiel #30
0
    def test_x_pow_minus_2(self):
        m = pe.ConcreteModel()
        m.x = pe.Var()
        m.y = pe.Var()
        m.c = pe.Constraint(expr=m.x**(-2) == m.y)

        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)
        self.assertEqual(m.y.lb, 0)
        self.assertEqual(m.y.ub, None)

        m.y.setlb(-5)
        m.y.setub(-1)
        with self.assertRaises(InfeasibleConstraintException):
            fbbt(m)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(0)
        with self.assertRaises(InfeasibleConstraintException):
            fbbt(m)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setub(1)
        m.y.setlb(0.25)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(0)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(None)
        m.x.setub(0)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, -1)
Beispiel #31
0
    def solve(self, model, **kwds):
        """Solve the model.
        Warning: this solver is still in beta. Keyword arguments subject to
        change. Undocumented keyword arguments definitely subject to change.
        Warning: at this point in time, if you try to use PSC or GBD with
        anything other than IPOPT as the NLP solver, bad things will happen.
        This is because the suffixes are not in place to extract dual values
        from the variable bounds for any other solver.
        TODO: fix needed with the GBD implementation.
        Args:
            model (Block): a Pyomo model or block to be solved
        """
        config = self.CONFIG(kwds.pop('options', {}))
        config.set_value(kwds)

        # configuration confirmation
        if config.single_tree:
            config.iteration_limit = 1
            config.add_slack = False
            config.add_nogood_cuts = False
            config.mip_solver = 'cplex_persistent'
            config.logger.info(
                "Single tree implementation is activated. The defalt MIP solver is 'cplex_persistent'"
            )
        # if the slacks fix to zero, just don't add them
        if config.max_slack == 0.0:
            config.add_slack = False

        if config.strategy == "GOA":
            config.add_nogood_cuts = True
            config.add_slack = True
            config.use_mcpp = True
            config.integer_to_binary = True
            config.use_dual = False
            config.use_fbbt = True

        if config.nlp_solver == "baron":
            config.use_dual = False
        # if ecp tolerance is not provided use bound tolerance
        if config.ecp_tolerance is None:
            config.ecp_tolerance = config.bound_tolerance

        # if the objective function is a constant, dual bound constraint is not added.
        obj = next(model.component_data_objects(ctype=Objective, active=True))
        if obj.expr.polynomial_degree() == 0:
            config.use_dual_bound = False

        solve_data = MindtPySolveData()
        solve_data.results = SolverResults()
        solve_data.timing = Container()
        solve_data.curr_int_sol = []
        solve_data.prev_int_sol = []

        if config.use_fbbt:
            fbbt(model)
            config.logger.info(
                "Use the fbbt to tighten the bounds of variables")

        solve_data.original_model = model
        solve_data.working_model = model.clone()
        if config.integer_to_binary:
            TransformationFactory('contrib.integer_to_binary'). \
                apply_to(solve_data.working_model)

        new_logging_level = logging.INFO if config.tee else None
        with time_code(solve_data.timing, 'total', is_main_timer=True), \
                lower_logger_level_to(config.logger, new_logging_level), \
                create_utility_block(solve_data.working_model, 'MindtPy_utils', solve_data):
            config.logger.info("---Starting MindtPy---")

            MindtPy = solve_data.working_model.MindtPy_utils
            setup_results_object(solve_data, config)
            process_objective(solve_data, config, use_mcpp=config.use_mcpp)

            # Save model initial values.
            solve_data.initial_var_values = list(
                v.value for v in MindtPy.variable_list)

            # Store the initial model state as the best solution found. If we
            # find no better solution, then we will restore from this copy.
            solve_data.best_solution_found = None
            solve_data.best_solution_found_time = None

            # Record solver name
            solve_data.results.solver.name = 'MindtPy' + str(config.strategy)

            # Validate the model to ensure that MindtPy is able to solve it.
            if not model_is_valid(solve_data, config):
                return

            # Create a model block in which to store the generated feasibility
            # slack constraints. Do not leave the constraints on by default.
            feas = MindtPy.MindtPy_feas = Block()
            feas.deactivate()
            feas.feas_constraints = ConstraintList(
                doc='Feasibility Problem Constraints')

            # Create a model block in which to store the generated linear
            # constraints. Do not leave the constraints on by default.
            lin = MindtPy.MindtPy_linear_cuts = Block()
            lin.deactivate()

            # Integer cuts exclude particular discrete decisions
            lin.integer_cuts = ConstraintList(doc='integer cuts')
            # Feasible integer cuts exclude discrete realizations that have
            # been explored via an NLP subproblem. Depending on model
            # characteristics, the user may wish to revisit NLP subproblems
            # (with a different initialization, for example). Therefore, these
            # cuts are not enabled by default.
            #
            # Note: these cuts will only exclude integer realizations that are
            # not already in the primary integer_cuts ConstraintList.
            lin.feasible_integer_cuts = ConstraintList(
                doc='explored integer cuts')
            lin.feasible_integer_cuts.deactivate()

            # Set up iteration counters
            solve_data.nlp_iter = 0
            solve_data.mip_iter = 0
            solve_data.mip_subiter = 0

            # set up bounds
            solve_data.LB = float('-inf')
            solve_data.UB = float('inf')
            solve_data.LB_progress = [solve_data.LB]
            solve_data.UB_progress = [solve_data.UB]
            if config.single_tree and config.add_nogood_cuts:
                solve_data.stored_bound = {}
            if config.strategy == 'GOA' and config.add_nogood_cuts:
                solve_data.num_no_good_cuts_added = {}

            # Set of NLP iterations for which cuts were generated
            lin.nlp_iters = Set(dimen=1)

            # Set of MIP iterations for which cuts were generated in ECP
            lin.mip_iters = Set(dimen=1)

            if config.feasibility_norm == 'L1' or config.feasibility_norm == 'L2':
                feas.nl_constraint_set = Set(
                    initialize=[
                        i
                        for i, constr in enumerate(MindtPy.constraint_list, 1)
                        if constr.body.polynomial_degree() not in (1, 0)
                    ],
                    doc="Integer index set over the nonlinear constraints."
                    "The set corresponds to the index of nonlinear constraint in constraint_set"
                )
                # Create slack variables for feasibility problem
                feas.slack_var = Var(feas.nl_constraint_set,
                                     domain=NonNegativeReals,
                                     initialize=1)
            else:
                feas.slack_var = Var(domain=NonNegativeReals, initialize=1)

            # Create slack variables for OA cuts
            if config.add_slack:
                lin.slack_vars = VarList(bounds=(0, config.max_slack),
                                         initialize=0,
                                         domain=NonNegativeReals)

            # Flag indicating whether the solution improved in the past
            # iteration or not
            solve_data.solution_improved = False

            if config.nlp_solver == 'ipopt':
                if not hasattr(solve_data.working_model, 'ipopt_zL_out'):
                    solve_data.working_model.ipopt_zL_out = Suffix(
                        direction=Suffix.IMPORT)
                if not hasattr(solve_data.working_model, 'ipopt_zU_out'):
                    solve_data.working_model.ipopt_zU_out = Suffix(
                        direction=Suffix.IMPORT)

            # Initialize the master problem
            with time_code(solve_data.timing, 'initialization'):
                MindtPy_initialize_master(solve_data, config)

            # Algorithm main loop
            with time_code(solve_data.timing, 'main loop'):
                MindtPy_iteration_loop(solve_data, config)

            if solve_data.best_solution_found is not None:
                # Update values in original model
                copy_var_list_values(from_list=solve_data.best_solution_found.
                                     MindtPy_utils.variable_list,
                                     to_list=MindtPy.variable_list,
                                     config=config)
                # MindtPy.objective_value.set_value(
                #     value(solve_data.working_objective_expr, exception=False))
                copy_var_list_values(
                    MindtPy.variable_list,
                    solve_data.original_model.component_data_objects(Var),
                    config)

            solve_data.results.problem.lower_bound = solve_data.LB
            solve_data.results.problem.upper_bound = solve_data.UB

        solve_data.results.solver.timing = solve_data.timing
        solve_data.results.solver.user_time = solve_data.timing.total
        solve_data.results.solver.wallclock_time = solve_data.timing.total

        solve_data.results.solver.iterations = solve_data.mip_iter
        solve_data.results.solver.best_solution_found_time = solve_data.best_solution_found_time

        if config.single_tree:
            solve_data.results.solver.num_nodes = solve_data.nlp_iter - \
                (1 if config.init_strategy == 'rNLP' else 0)

        return solve_data.results
Beispiel #32
0
def relax(model, descend_into=None, in_place=False, use_fbbt=True):
    if not in_place:
        m = model.clone()
    else:
        m = model

    if descend_into is None:
        descend_into = (pe.Block, Disjunct)

    aux_var_map = dict()
    counter_dict = dict()
    degree_map = ComponentMap()

    for c in m.component_data_objects(ctype=Constraint, active=True, descend_into=descend_into, sort=True):
        body_degree = polynomial_degree(c.body)
        if body_degree is not None:
            if body_degree <= 1:
                continue

        if c.lower is not None and c.upper is not None:
            relaxation_side = RelaxationSide.BOTH
        elif c.lower is not None:
            relaxation_side = RelaxationSide.OVER
        elif c.upper is not None:
            relaxation_side = RelaxationSide.UNDER
        else:
            raise ValueError('Encountered a constraint without a lower or an upper bound: ' + str(c))

        parent_block = c.parent_block()
        relaxation_side_map = ComponentMap()
        relaxation_side_map[c.body] = relaxation_side

        if parent_block in counter_dict:
            counter = counter_dict[parent_block]
        else:
            parent_block.relaxations = pe.Block()
            parent_block.aux_vars = pe.VarList()
            parent_block.aux_cons = pe.ConstraintList()
            counter = RelaxationCounter()
            counter_dict[parent_block] = counter

        new_body = _relax_expr(expr=c.body, aux_var_map=aux_var_map, parent_block=parent_block,
                               relaxation_side_map=relaxation_side_map, counter=counter, degree_map=degree_map)
        lb = c.lower
        ub = c.upper
        parent_block.aux_cons.add(pe.inequality(lb, new_body, ub))
        parent_component = c.parent_component()
        if parent_component.is_indexed():
            del parent_component[c.index()]
        else:
            parent_block.del_component(c)

    for c in m.component_data_objects(ctype=pe.Objective, active=True, descend_into=descend_into, sort=True):
        degree = polynomial_degree(c.expr)
        if degree is not None:
            if degree <= 1:
                continue

        if c.sense == pe.minimize:
            relaxation_side = RelaxationSide.UNDER
        elif c.sense == pe.maximize:
            relaxation_side = RelaxationSide.OVER
        else:
            raise ValueError('Encountered an objective with an unrecognized sense: ' + str(c))

        parent_block = c.parent_block()
        relaxation_side_map = ComponentMap()
        relaxation_side_map[c.expr] = relaxation_side

        if parent_block in counter_dict:
            counter = counter_dict[parent_block]
        else:
            parent_block.relaxations = pe.Block()
            parent_block.aux_vars = pe.VarList()
            parent_block.aux_cons = pe.ConstraintList()
            counter = RelaxationCounter()
            counter_dict[parent_block] = counter

        if not hasattr(parent_block, 'aux_objectives'):
            parent_block.aux_objectives = pe.ObjectiveList()

        new_body = _relax_expr(expr=c.expr, aux_var_map=aux_var_map, parent_block=parent_block,
                               relaxation_side_map=relaxation_side_map, counter=counter, degree_map=degree_map)
        sense = c.sense
        parent_block.aux_objectives.add(new_body, sense=sense)
        parent_component = c.parent_component()
        if parent_component.is_indexed():
            del parent_component[c.index()]
        else:
            parent_block.del_component(c)

    if use_fbbt:
        for _aux_var, relaxation in aux_var_map.values():
            relaxation.rebuild(build_nonlinear_constraint=True)

        fbbt(m, deactivate_satisfied_constraints=True)

        for _aux_var, relaxation in aux_var_map.values():
            relaxation.use_linear_relaxation = True
            relaxation.rebuild()
    else:
        for _aux_var, relaxation in aux_var_map.values():
            relaxation.use_linear_relaxation = True
            relaxation.rebuild()

    return m
Beispiel #33
0
def solve_linear_GDP(linear_GDP_model, solve_data, config):
    """Solves the linear GDP model and attempts to resolve solution issues."""
    m = linear_GDP_model
    GDPopt = m.GDPopt_utils
    # Transform disjunctions
    _bigm = TransformationFactory('gdp.bigm')
    _bigm.handlers[Port] = False
    _bigm.apply_to(m)

    preprocessing_transformations = [
        # # Propagate variable bounds
        # 'contrib.propagate_eq_var_bounds',
        # # Detect fixed variables
        # 'contrib.detect_fixed_vars',
        # # Propagate fixed variables
        # 'contrib.propagate_fixed_vars',
        # # Remove zero terms in linear expressions
        # 'contrib.remove_zero_terms',
        # # Remove terms in equal to zero summations
        # 'contrib.propagate_zero_sum',
        # # Transform bound constraints
        # 'contrib.constraints_to_var_bounds',
        # # Detect fixed variables
        # 'contrib.detect_fixed_vars',
        # # Remove terms in equal to zero summations
        # 'contrib.propagate_zero_sum',
        # Remove trivial constraints
        'contrib.deactivate_trivial_constraints',
    ]
    if config.mip_presolve:
        try:
            fbbt(m, integer_tol=config.integer_tolerance)
            for xfrm in preprocessing_transformations:
                TransformationFactory(xfrm).apply_to(m)
        except InfeasibleConstraintException:
            config.logger.debug("MIP preprocessing detected infeasibility.")
            mip_result = MasterProblemResult()
            mip_result.feasible = False
            mip_result.var_values = list(v.value for v in GDPopt.variable_list)
            mip_result.pyomo_results = SolverResults()
            mip_result.pyomo_results.solver.termination_condition = tc.error
            mip_result.disjunct_values = list(disj.indicator_var.value
                                              for disj in GDPopt.disjunct_list)
            return mip_result

    # Deactivate extraneous IMPORT/EXPORT suffixes
    getattr(m, 'ipopt_zL_out', _DoNothing()).deactivate()
    getattr(m, 'ipopt_zU_out', _DoNothing()).deactivate()

    # Create solver, check availability
    if not SolverFactory(config.mip_solver).available():
        raise RuntimeError("MIP solver %s is not available." %
                           config.mip_solver)

    # Callback immediately before solving MIP master problem
    config.call_before_master_solve(m, solve_data)

    try:
        with SuppressInfeasibleWarning():
            mip_args = dict(config.mip_solver_args)
            elapsed = get_main_elapsed_time(solve_data.timing)
            remaining = max(config.time_limit - elapsed, 1)
            if config.mip_solver == 'gams':
                mip_args['add_options'] = mip_args.get('add_options', [])
                mip_args['add_options'].append('option reslim=%s;' % remaining)
            elif config.mip_solver == 'multisolve':
                mip_args['time_limit'] = min(
                    mip_args.get('time_limit', float('inf')), remaining)
            results = SolverFactory(config.mip_solver).solve(m, **mip_args)
    except RuntimeError as e:
        if 'GAMS encountered an error during solve.' in str(e):
            config.logger.warning(
                "GAMS encountered an error in solve. Treating as infeasible.")
            mip_result = MasterProblemResult()
            mip_result.feasible = False
            mip_result.var_values = list(v.value for v in GDPopt.variable_list)
            mip_result.pyomo_results = SolverResults()
            mip_result.pyomo_results.solver.termination_condition = tc.error
            mip_result.disjunct_values = list(disj.indicator_var.value
                                              for disj in GDPopt.disjunct_list)
            return mip_result
        else:
            raise
    terminate_cond = results.solver.termination_condition
    if terminate_cond is tc.infeasibleOrUnbounded:
        # Linear solvers will sometimes tell me that it's infeasible or
        # unbounded during presolve, but fails to distinguish. We need to
        # resolve with a solver option flag on.
        results, terminate_cond = distinguish_mip_infeasible_or_unbounded(
            m, config)
    if terminate_cond is tc.unbounded:
        # Solution is unbounded. Add an arbitrary bound to the objective and resolve.
        # This occurs when the objective is nonlinear. The nonlinear objective is moved
        # to the constraints, and deactivated for the linear master problem.
        obj_bound = 1E15
        config.logger.warning(
            'Linear GDP was unbounded. '
            'Resolving with arbitrary bound values of (-{0:.10g}, {0:.10g}) on the objective. '
            'Check your initialization routine.'.format(obj_bound))
        main_objective = next(m.component_data_objects(Objective, active=True))
        GDPopt.objective_bound = Constraint(expr=(-obj_bound,
                                                  main_objective.expr,
                                                  obj_bound))
        with SuppressInfeasibleWarning():
            results = SolverFactory(config.mip_solver).solve(
                m, **config.mip_solver_args)
        terminate_cond = results.solver.termination_condition

    # Build and return results object
    mip_result = MasterProblemResult()
    mip_result.feasible = True
    mip_result.var_values = list(v.value for v in GDPopt.variable_list)
    mip_result.pyomo_results = results
    mip_result.disjunct_values = list(disj.indicator_var.value
                                      for disj in GDPopt.disjunct_list)

    if terminate_cond in {tc.optimal, tc.locallyOptimal, tc.feasible}:
        pass
    elif terminate_cond is tc.infeasible:
        config.logger.info(
            'Linear GDP is now infeasible. '
            'GDPopt has finished exploring feasible discrete configurations.')
        mip_result.feasible = False
    elif terminate_cond is tc.maxTimeLimit:
        # TODO check that status is actually ok and everything is feasible
        config.logger.info(
            'Unable to optimize linear GDP problem within time limit. '
            'Using current solver feasible solution.')
    elif (terminate_cond is tc.other
          and results.solution.status is SolutionStatus.feasible):
        # load the solution and suppress the warning message by setting
        # solver status to ok.
        config.logger.info('Linear GDP solver reported feasible solution, '
                           'but not guaranteed to be optimal.')
    else:
        raise ValueError('GDPopt unable to handle linear GDP '
                         'termination condition '
                         'of %s. Solver message: %s' %
                         (terminate_cond, results.solver.message))

    return mip_result
Beispiel #34
0
def relax(model, descend_into=None, in_place=False, use_fbbt=True, fbbt_options=None):
    """
    Create a convex relaxation of the model.

    Parameters
    ----------
    model: pyomo.core.base.block._BlockData or pyomo.core.base.PyomoModel.ConcreteModel
        The model or block to be relaxed
    descend_into: type or tuple of type, optional
        The types of pyomo components that should be checked for constraints to be relaxed. The
        default is (Block, Disjunct).
    in_place: bool, optional
        If False (default=False), model will be cloned, and the clone will be relaxed. 
        If True, then model will be modified in place.
    use_fbbt: bool, optional
        If True (default=True), then FBBT will be used to tighten variable bounds. If False, 
        FBBT will not be used.
    fbbt_options: dict, optional
        The options to pass to the call to fbbt. See pyomo.contrib.fbbt.fbbt.fbbt for details.

    Returns
    -------
    m: pyomo.core.base.block._BlockData or pyomo.core.base.PyomoModel.ConcreteModel
        The relaxed model
    """
    """
    For now, we will use FBBT both before relaxing the model and after relaxing the model. The reason we need to 
    do it before relaxing the model is that the variable bounds will affect the structure of the relaxation. For 
    example, if we need to relax x**3 and x >= 0, then we know x**3 is convex, and we can relax it as a 
    convex, univariate function. However, if x can be positive or negative, then x**3 is neither convex nor concave.
    In this case, we relax it by reformulating it as x * x**2. The hope is that performing FBBT before relaxing 
    the model will help identify things like x >= 0 and therefore x**3 is convex. The correct way to do this is to 
    update the relaxation classes so that the original expression is known, and the best relaxation can be used 
    anytime the variable bounds are updated. For example, suppose the model is relaxed and, only after OBBT is 
    performed, we find out x >= 0. We should be able to easily update the relaxation so that x**3 is then relaxed 
    as a convex univariate function. The reason FBBT needs to be performed after relaxing the model is that 
    we want to make sure that all of the auxilliary variables introduced get tightened bounds. The correct way to 
    handle this is to perform FBBT with the original model with suspect, which forms a DAG. Each auxilliary variable 
    introduced in the relaxed model corresponds to a node in the DAG. If we use suspect, then we can easily 
    update the bounds of the auxilliary variables without performing FBBT a second time.
    """
    if not in_place:
        m = model.clone()
    else:
        m = model

    if fbbt_options is None:
        fbbt_options = dict()

    if use_fbbt:
        fbbt(m, **fbbt_options)

    if descend_into is None:
        descend_into = (pe.Block, Disjunct)

    aux_var_map = dict()
    counter_dict = dict()
    degree_map = ComponentMap()

    for c in nonrelaxation_component_data_objects(m, ctype=Constraint, active=True, descend_into=descend_into, sort=True):
        body_degree = polynomial_degree(c.body)
        if body_degree is not None:
            if body_degree <= 1:
                continue

        if c.lower is not None and c.upper is not None:
            relaxation_side = RelaxationSide.BOTH
        elif c.lower is not None:
            relaxation_side = RelaxationSide.OVER
        elif c.upper is not None:
            relaxation_side = RelaxationSide.UNDER
        else:
            raise ValueError('Encountered a constraint without a lower or an upper bound: ' + str(c))

        parent_block = c.parent_block()
        relaxation_side_map = ComponentMap()
        relaxation_side_map[c.body] = relaxation_side

        if parent_block in counter_dict:
            counter = counter_dict[parent_block]
        else:
            parent_block.relaxations = pe.Block()
            parent_block.aux_vars = pe.VarList()
            parent_block.aux_cons = pe.ConstraintList()
            counter = RelaxationCounter()
            counter_dict[parent_block] = counter

        new_body = _relax_expr(expr=c.body, aux_var_map=aux_var_map, parent_block=parent_block,
                               relaxation_side_map=relaxation_side_map, counter=counter, degree_map=degree_map)
        lb = c.lower
        ub = c.upper
        parent_block.aux_cons.add(pe.inequality(lb, new_body, ub))
        parent_component = c.parent_component()
        if parent_component.is_indexed():
            del parent_component[c.index()]
        else:
            parent_block.del_component(c)

    for c in nonrelaxation_component_data_objects(m, ctype=pe.Objective, active=True, descend_into=descend_into, sort=True):
        degree = polynomial_degree(c.expr)
        if degree is not None:
            if degree <= 1:
                continue

        if c.sense == pe.minimize:
            relaxation_side = RelaxationSide.UNDER
        elif c.sense == pe.maximize:
            relaxation_side = RelaxationSide.OVER
        else:
            raise ValueError('Encountered an objective with an unrecognized sense: ' + str(c))

        parent_block = c.parent_block()
        relaxation_side_map = ComponentMap()
        relaxation_side_map[c.expr] = relaxation_side

        if parent_block in counter_dict:
            counter = counter_dict[parent_block]
        else:
            parent_block.relaxations = pe.Block()
            parent_block.aux_vars = pe.VarList()
            parent_block.aux_cons = pe.ConstraintList()
            counter = RelaxationCounter()
            counter_dict[parent_block] = counter

        if not hasattr(parent_block, 'aux_objectives'):
            parent_block.aux_objectives = pe.ObjectiveList()

        new_body = _relax_expr(expr=c.expr, aux_var_map=aux_var_map, parent_block=parent_block,
                               relaxation_side_map=relaxation_side_map, counter=counter, degree_map=degree_map)
        sense = c.sense
        parent_block.aux_objectives.add(new_body, sense=sense)
        parent_component = c.parent_component()
        if parent_component.is_indexed():
            del parent_component[c.index()]
        else:
            parent_block.del_component(c)

    if use_fbbt:
        for _aux_var, relaxation in aux_var_map.values():
            relaxation.rebuild(build_nonlinear_constraint=True)

        tmp_fbbt_options = dict(fbbt_options)
        tmp_fbbt_options['deactivate_satisfied_constraints'] = False
        fbbt(m, **tmp_fbbt_options)

        for _aux_var, relaxation in aux_var_map.values():
            relaxation.use_linear_relaxation = True
            relaxation.rebuild()
    else:
        for _aux_var, relaxation in aux_var_map.values():
            relaxation.use_linear_relaxation = True
            relaxation.rebuild()

    return m
def plot_feasible_region_2d(relaxation, show_plot=True, num_pts=30, tol=1e-4):
    if not isinstance(relaxation,
                      (PWXSquaredRelaxation, PWUnivariateRelaxation,
                       PWCosRelaxation, PWSinRelaxation, PWArctanRelaxation)):
        raise NotImplementedError('Plotting is not supported for {0}.'.format(
            type(relaxation)))

    x = relaxation.get_rhs_vars()[0]
    w = relaxation.get_aux_var()

    rel_name = relaxation.local_name
    x_name = x.local_name
    w_name = w.local_name

    rel_parent = relaxation.parent_block()
    x_parent = x.parent_block()
    w_parent = w.parent_block()

    rel_parent.del_component(relaxation)
    x_parent.del_component(x)
    w_parent.del_component(w)

    orig_xlb = x.lb
    orig_xub = x.ub
    orig_wlb = w.lb
    orig_wub = w.ub

    fbbt(relaxation)

    xlb = pe.value(x.lb)
    xub = pe.value(x.ub)
    wlb = pe.value(w.lb)
    wub = pe.value(w.ub)

    x_list = np.linspace(xlb, xub, num_pts)
    w_list = np.linspace(wlb, wub, num_pts)

    w_true = list()
    rhs_expr = relaxation.get_rhs_expr()
    for _x in x_list:
        x.value = float(_x)
        w_true.append(pe.value(rhs_expr))
    plt.plot(x_list, w_true)

    x_list = [float(i) for i in x_list]
    w_list = [float(i) for i in w_list]

    m = pe.ConcreteModel()
    m.x = x
    m.w = w
    m.b = relaxation
    opt = pe.SolverFactory('gurobi_persistent')
    opt.options['BarQCPConvTol'] = 1e-8
    opt.options['FeasibilityTol'] = 1e-8
    opt.set_instance(m)

    feasible_x = list()
    feasible_w = list()

    for _xval in x_list:
        for _wval in w_list:
            x.fix(_xval)
            if hasattr(m, 'obj'):
                del m.obj
            m.obj = pe.Objective(expr=(w - _wval)**2)
            opt.update_var(x)
            opt.set_objective(m.obj)
            res = opt.solve(load_solutions=False, save_results=False)
            if res.solver.termination_condition != pe.TerminationCondition.optimal:
                raise RuntimeError(
                    'Could not produce plot because a feasiblity test failed.')
            opt.load_vars([w])
            if abs(pe.value(w.value) - _wval) <= tol:
                feasible_x.append(_xval)
                feasible_w.append(_wval)

    plt.scatter(feasible_x, feasible_w, 5.0)
    plt.xlabel('x')
    plt.ylabel('y')
    if show_plot:
        plt.show()

    m.del_component(relaxation)
    m.del_component(x)
    m.del_component(w)
    del m
    rel_parent.add_component(rel_name, relaxation)
    x_parent.add_component(x_name, x)
    w_parent.add_component(w_name, w)

    x.unfix()
    x.setlb(orig_xlb)
    x.setub(orig_xub)
    w.setlb(orig_wlb)
    w.setub(orig_wub)
Beispiel #36
0
def enumerate_solutions():
    import time
    feed_choices = ['cheap', 'expensive']
    feed_compressor_choices = ['single_stage', 'two_stage']
    reactor_choices = ['cheap', 'expensive']
    recycle_compressor_choices = ['single_stage', 'two_stage']

    print('{0:<20}{1:<20}{2:<20}{3:<20}{4:<20}{5:<20}'.format(
        'feed choice', 'feed compressor', 'reactor choice',
        'recycle compressor', 'termination cond', 'profit'))
    since = time.time()
    for feed_choice in feed_choices:
        for feed_compressor_choice in feed_compressor_choices:
            for reactor_choice in reactor_choices:
                for recycle_compressor_choice in recycle_compressor_choices:
                    m = MethanolModel()
                    m = m.model
                    for _d in m.component_data_objects(gdp.Disjunct,
                                                       descend_into=True,
                                                       active=True,
                                                       sort=True):
                        _d.BigM = pe.Suffix()
                        for _c in _d.component_data_objects(pe.Constraint,
                                                            descend_into=True,
                                                            active=True,
                                                            sort=True):
                            lb, ub = compute_bounds_on_expr(_c.body)
                            _d.BigM[_c] = max(abs(lb), abs(ub))

                    if feed_choice == 'cheap':
                        m.cheap_feed_disjunct.indicator_var.fix(1)
                        m.expensive_feed_disjunct.indicator_var.fix(0)
                    else:
                        m.cheap_feed_disjunct.indicator_var.fix(0)
                        m.expensive_feed_disjunct.indicator_var.fix(1)

                    if feed_compressor_choice == 'single_stage':
                        m.single_stage_feed_compressor_disjunct.indicator_var.fix(
                            1)
                        m.two_stage_feed_compressor_disjunct.indicator_var.fix(
                            0)
                    else:
                        m.single_stage_feed_compressor_disjunct.indicator_var.fix(
                            0)
                        m.two_stage_feed_compressor_disjunct.indicator_var.fix(
                            1)

                    if reactor_choice == 'cheap':
                        m.cheap_reactor.indicator_var.fix(1)
                        m.expensive_reactor.indicator_var.fix(0)
                    else:
                        m.cheap_reactor.indicator_var.fix(0)
                        m.expensive_reactor.indicator_var.fix(1)

                    if recycle_compressor_choice == 'single_stage':
                        m.single_stage_recycle_compressor_disjunct.indicator_var.fix(
                            1)
                        m.two_stage_recycle_compressor_disjunct.indicator_var.fix(
                            0)
                    else:
                        m.single_stage_recycle_compressor_disjunct.indicator_var.fix(
                            0)
                        m.two_stage_recycle_compressor_disjunct.indicator_var.fix(
                            1)

                    pe.TransformationFactory('gdp.fix_disjuncts').apply_to(m)

                    fbbt(m, deactivate_satisfied_constraints=True)
                    fix_vars_with_equal_bounds(m)

                    for v in m.component_data_objects(pe.Var,
                                                      descend_into=True):
                        if not v.is_fixed():
                            if v.has_lb() and v.has_ub():
                                v.value = 0.5 * (v.lb + v.ub)
                            else:
                                v.value = 1.0

                    opt = pe.SolverFactory('ipopt')
                    res = opt.solve(m, tee=False)
                    print('{0:<20}{1:<20}{2:<20}{3:<20}{4:<20}{5:<20}'.format(
                        feed_choice, feed_compressor_choice, reactor_choice,
                        recycle_compressor_choice,
                        str(res.solver.termination_condition),
                        str(-pe.value(m.objective))))
    time_elapsed = time.time() - since
    print('The code run {:.0f}m {:.0f}s'.format(time_elapsed // 60,
                                                time_elapsed % 60))

    return m
Beispiel #37
0
def set_up_solve_data(model, config):
    """Set up the solve data.

    Parameters
    ----------
    model : Pyomo model
        The original model to be solved in MindtPy.
    config : ConfigBlock
        The specific configurations for MindtPy.

    Returns
    -------
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    """
    solve_data = MindtPySolveData()
    solve_data.results = SolverResults()
    solve_data.timing = Bunch()
    solve_data.curr_int_sol = []
    solve_data.should_terminate = False
    solve_data.integer_list = []

    # if the objective function is a constant, dual bound constraint is not added.
    obj = next(model.component_data_objects(ctype=Objective, active=True))
    if obj.expr.polynomial_degree() == 0:
        config.use_dual_bound = False

    if config.use_fbbt:
        fbbt(model)
        # TODO: logging_level is not logging.INFO here
        config.logger.info('Use the fbbt to tighten the bounds of variables')

    solve_data.original_model = model
    solve_data.working_model = model.clone()

    # Set up iteration counters
    solve_data.nlp_iter = 0
    solve_data.mip_iter = 0
    solve_data.mip_subiter = 0
    solve_data.nlp_infeasible_counter = 0
    if config.init_strategy == 'FP':
        solve_data.fp_iter = 1

    # set up bounds
    if obj.sense == minimize:
        solve_data.primal_bound = float('inf')
        solve_data.dual_bound = float('-inf')
    else:
        solve_data.primal_bound = float('-inf')
        solve_data.dual_bound = float('inf')
    solve_data.primal_bound_progress = [solve_data.primal_bound]
    solve_data.dual_bound_progress = [solve_data.dual_bound]
    solve_data.primal_bound_progress_time = [0]
    solve_data.dual_bound_progress_time = [0]
    solve_data.abs_gap = float('inf')
    solve_data.rel_gap = float('inf')
    solve_data.log_formatter = ' {:>9}   {:>15}   {:>15g}   {:>12g}   {:>12g}   {:>7.2%}   {:>7.2f}'
    solve_data.fixed_nlp_log_formatter = '{:1}{:>9}   {:>15}   {:>15g}   {:>12g}   {:>12g}   {:>7.2%}   {:>7.2f}'
    solve_data.log_note_formatter = ' {:>9}   {:>15}   {:>15}'
    if config.add_regularization is not None:
        if config.add_regularization in {
                'level_L1', 'level_L_infinity', 'grad_lag'
        }:
            solve_data.regularization_mip_type = 'MILP'
        elif config.add_regularization in {
                'level_L2', 'hess_lag', 'hess_only_lag', 'sqp_lag'
        }:
            solve_data.regularization_mip_type = 'MIQP'

    if config.single_tree and (config.add_no_good_cuts
                               or config.use_tabu_list):
        solve_data.stored_bound = {}
    if config.strategy == 'GOA' and (config.add_no_good_cuts
                                     or config.use_tabu_list):
        solve_data.num_no_good_cuts_added = {}

    # Flag indicating whether the solution improved in the past
    # iteration or not
    solve_data.primal_bound_improved = False
    solve_data.dual_bound_improved = False

    if config.nlp_solver == 'ipopt':
        if not hasattr(solve_data.working_model, 'ipopt_zL_out'):
            solve_data.working_model.ipopt_zL_out = Suffix(
                direction=Suffix.IMPORT)
        if not hasattr(solve_data.working_model, 'ipopt_zU_out'):
            solve_data.working_model.ipopt_zU_out = Suffix(
                direction=Suffix.IMPORT)

    if config.quadratic_strategy == 0:
        solve_data.mip_objective_polynomial_degree = {0, 1}
        solve_data.mip_constraint_polynomial_degree = {0, 1}
    elif config.quadratic_strategy == 1:
        solve_data.mip_objective_polynomial_degree = {0, 1, 2}
        solve_data.mip_constraint_polynomial_degree = {0, 1}
    elif config.quadratic_strategy == 2:
        solve_data.mip_objective_polynomial_degree = {0, 1, 2}
        solve_data.mip_constraint_polynomial_degree = {0, 1, 2}

    return solve_data
Beispiel #38
0
def _solve_rnGDP_subproblem(model, solve_data):
    config = solve_data.config
    subproblem = TransformationFactory('gdp.bigm').create_using(model)
    obj_sense_correction = solve_data.objective_sense != minimize

    try:
        with SuppressInfeasibleWarning():
            try:
                fbbt(subproblem, integer_tol=config.integer_tolerance)
            except InfeasibleConstraintException:
                copy_var_list_values(  # copy variable values, even if errored
                    from_list=subproblem.GDPopt_utils.variable_list,
                    to_list=model.GDPopt_utils.variable_list,
                    config=config,
                    ignore_integrality=True)
                return float('inf'), float('inf')
            minlp_args = dict(config.minlp_solver_args)
            if config.minlp_solver == 'gams':
                elapsed = get_main_elapsed_time(solve_data.timing)
                remaining = max(config.time_limit - elapsed, 1)
                minlp_args['add_options'] = minlp_args.get('add_options', [])
                minlp_args['add_options'].append('option reslim=%s;' %
                                                 remaining)
            result = SolverFactory(config.minlp_solver).solve(
                subproblem, **minlp_args)
    except RuntimeError as e:
        config.logger.warning(
            "Solver encountered RuntimeError. Treating as infeasible. "
            "Msg: %s\n%s" % (str(e), traceback.format_exc()))
        copy_var_list_values(  # copy variable values, even if errored
            from_list=subproblem.GDPopt_utils.variable_list,
            to_list=model.GDPopt_utils.variable_list,
            config=config,
            ignore_integrality=True)
        return float('inf'), float('inf')

    term_cond = result.solver.termination_condition
    if term_cond == tc.optimal:
        assert result.solver.status is SolverStatus.ok
        lb = result.problem.lower_bound if not obj_sense_correction else -result.problem.upper_bound
        ub = result.problem.upper_bound if not obj_sense_correction else -result.problem.lower_bound
        copy_var_list_values(
            from_list=subproblem.GDPopt_utils.variable_list,
            to_list=model.GDPopt_utils.variable_list,
            config=config,
        )
        return lb, ub
    elif term_cond == tc.locallyOptimal or term_cond == tc.feasible:
        assert result.solver.status is SolverStatus.ok
        lb = result.problem.lower_bound if not obj_sense_correction else -result.problem.upper_bound
        ub = result.problem.upper_bound if not obj_sense_correction else -result.problem.lower_bound
        # TODO handle LB absent
        copy_var_list_values(
            from_list=subproblem.GDPopt_utils.variable_list,
            to_list=model.GDPopt_utils.variable_list,
            config=config,
        )
        return lb, ub
    elif term_cond == tc.unbounded:
        copy_var_list_values(from_list=subproblem.GDPopt_utils.variable_list,
                             to_list=model.GDPopt_utils.variable_list,
                             config=config,
                             ignore_integrality=True)
        return float('-inf'), float('-inf')
    elif term_cond == tc.infeasible:
        copy_var_list_values(from_list=subproblem.GDPopt_utils.variable_list,
                             to_list=model.GDPopt_utils.variable_list,
                             config=config,
                             ignore_integrality=True)
        return float('inf'), float('inf')
    else:
        config.logger.warning(
            "Unknown termination condition of %s. Treating as infeasible." %
            term_cond)
        copy_var_list_values(from_list=subproblem.GDPopt_utils.variable_list,
                             to_list=model.GDPopt_utils.variable_list,
                             config=config,
                             ignore_integrality=True)
        return float('inf'), float('inf')
Beispiel #39
0
def create_relaxation_of_polar_acopf(model_data,
                                     include_soc=True,
                                     use_linear_relaxation=False):
    if not coramin_available:
        raise ImportError(
            'Cannot create polar relaxation unless coramin is available.')

    model, md = _create_base_relaxation(model_data)
    branches = dict(md.elements(element_type='branch'))
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    bus_pairs = zip_items(branch_attrs['from_bus'], branch_attrs['to_bus'])
    unique_bus_pairs = list(
        OrderedDict((val, None) for idx, val in bus_pairs.items()).keys())

    # declare the polar voltages
    libbus.declare_var_vm(model,
                          bus_attrs['names'],
                          initialize=bus_attrs['vm'],
                          bounds=zip_items(bus_attrs['v_min'],
                                           bus_attrs['v_max']))

    va_bounds = {k: (-pi, pi) for k in bus_attrs['va']}
    libbus.declare_var_va(model,
                          bus_attrs['names'],
                          initialize=bus_attrs['va'],
                          bounds=va_bounds)

    # fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    ref_angle = md.data['system']['reference_bus_angle']
    model.va[ref_bus].fix(radians(ref_angle))

    # relate c, s, and vmsq to vm and va
    libbus.declare_eq_vmsq(model=model,
                           index_set=bus_attrs['names'],
                           coordinate_type=CoordinateType.POLAR)
    libbranch.declare_eq_c(model=model,
                           index_set=unique_bus_pairs,
                           coordinate_type=CoordinateType.POLAR)
    libbranch.declare_eq_s(model=model,
                           index_set=unique_bus_pairs,
                           coordinate_type=CoordinateType.POLAR)

    # declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        coordinate_type=CoordinateType.POLAR)

    fbbt(model, deactivate_satisfied_constraints=False)
    model = coramin.relaxations.relax(model, in_place=True, use_fbbt=False)
    if not use_linear_relaxation:
        for b in model.component_data_objects(pe.Block,
                                              descend_into=True,
                                              active=True,
                                              sort=True):
            if isinstance(b, (coramin.relaxations.BaseRelaxation,
                              coramin.relaxations.BaseRelaxationData)):
                if polynomial_degree(b.get_rhs_expr()) == 2:
                    if not isinstance(
                            b,
                        (coramin.relaxations.PWMcCormickRelaxation,
                         coramin.relaxations.PWMcCormickRelaxationData)):
                        b.use_linear_relaxation = False
                        b.rebuild()

    if include_soc:
        libbranch.declare_ineq_soc(
            model=model,
            index_set=unique_bus_pairs,
            use_outer_approximation=use_linear_relaxation)

    return model, md
Beispiel #40
0
    def test_x_sq(self):
        m = pe.ConcreteModel()
        m.x = pe.Var()
        m.y = pe.Var()
        m.c = pe.Constraint(expr=m.x**2 == m.y)

        fbbt(m)
        self.assertEqual(m.x.lb, None)
        self.assertEqual(m.x.ub, None)
        self.assertEqual(m.y.lb, 0)
        self.assertEqual(m.y.ub, None)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(1)
        m.y.setub(4)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(0)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(-0.5)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, 1)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(-1)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -1)
        self.assertAlmostEqual(m.x.ub, 2)

        m.x.setlb(None)
        m.x.setub(0)
        fbbt(m)
        self.assertAlmostEqual(m.x.lb, -2)
        self.assertAlmostEqual(m.x.ub, -1)

        m.x.setlb(None)
        m.x.setub(None)
        m.y.setlb(-5)
        m.y.setub(-1)
        with self.assertRaises(ValueError):
            fbbt(m)

        m.y.setub(0)
        fbbt(m)
        self.assertEqual(m.x.lb, 0)
        self.assertEqual(m.x.ub, 0)