Example #1
0
 def test_var(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-1, 1), initialize=3)
     mc_var = mc(m.x)
     self.assertEqual(mc_var.lower(), -1)
     self.assertEqual(mc_var.upper(), 1)
     m.no_ub = Var(bounds=(0, None), initialize=3)
     output = StringIO()
     with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING):
         mc_var = mc(m.no_ub)
         self.assertIn("Var no_ub missing upper bound.",
                       output.getvalue().strip())
         self.assertEqual(mc_var.lower(), 0)
         self.assertEqual(mc_var.upper(), 500000)
     m.no_lb = Var(bounds=(None, -3), initialize=-1)
     output = StringIO()
     with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING):
         mc_var = mc(m.no_lb)
         self.assertIn("Var no_lb missing lower bound.",
                       output.getvalue().strip())
         self.assertEqual(mc_var.lower(), -500000)
         self.assertEqual(mc_var.upper(), -3)
     m.no_val = Var(bounds=(0, 1))
     output = StringIO()
     with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING):
         mc_var = mc(m.no_val)
         mc_var.subcv()
         self.assertIn("Var no_val missing value.",
                       output.getvalue().strip())
         self.assertEqual(mc_var.lower(), 0)
         self.assertEqual(mc_var.upper(), 1)
Example #2
0
 def test_var(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-1, 1), initialize=3)
     mc_var = mc(m.x)
     self.assertEqual(mc_var.lower(), -1)
     self.assertEqual(mc_var.upper(), 1)
     m.no_ub = Var(bounds=(0, None), initialize=3)
     output = StringIO()
     with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING):
         mc_var = mc(m.no_ub)
         self.assertIn("Var no_ub missing upper bound.",
                       output.getvalue().strip())
         self.assertEqual(mc_var.lower(), 0)
         self.assertEqual(mc_var.upper(), 500000)
     m.no_lb = Var(bounds=(None, -3), initialize=-1)
     output = StringIO()
     with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING):
         mc_var = mc(m.no_lb)
         self.assertIn("Var no_lb missing lower bound.",
                       output.getvalue().strip())
         self.assertEqual(mc_var.lower(), -500000)
         self.assertEqual(mc_var.upper(), -3)
     m.no_val = Var(bounds=(0, 1))
     output = StringIO()
     with LoggingIntercept(output, 'pyomo.contrib.mcpp', logging.WARNING):
         mc_var = mc(m.no_val)
         mc_var.subcv()
         self.assertIn("Var no_val missing value.",
                       output.getvalue().strip())
         self.assertEqual(mc_var.lower(), 0)
         self.assertEqual(mc_var.upper(), 1)
Example #3
0
 def test_trig(self):
     m = ConcreteModel()
     m.x = Var(bounds=(pi / 4, pi / 2), initialize=pi / 4)
     mc_expr = mc(tan(atan((m.x))))
     self.assertAlmostEqual(mc_expr.lower(), pi / 4)
     self.assertAlmostEqual(mc_expr.upper(), pi / 2)
     m.y = Var(bounds=(0, sin(pi / 4)), initialize=0)
     mc_expr = mc(asin((m.y)))
     self.assertEqual(mc_expr.lower(), 0)
     self.assertAlmostEqual(mc_expr.upper(), pi / 4)
     m.z = Var(bounds=(0, cos(pi / 4)), initialize=0)
     mc_expr = mc(acos((m.z)))
     self.assertAlmostEqual(mc_expr.lower(), pi / 4)
     self.assertAlmostEqual(mc_expr.upper(), pi / 2)
Example #4
0
 def test_trig(self):
     m = ConcreteModel()
     m.x = Var(bounds=(pi / 4, pi / 2), initialize=pi / 4)
     mc_expr = mc(tan(atan((m.x))))
     self.assertAlmostEqual(mc_expr.lower(), pi / 4)
     self.assertAlmostEqual(mc_expr.upper(), pi / 2)
     m.y = Var(bounds=(0, sin(pi / 4)), initialize=0)
     mc_expr = mc(asin((m.y)))
     self.assertEqual(mc_expr.lower(), 0)
     self.assertAlmostEqual(mc_expr.upper(), pi / 4)
     m.z = Var(bounds=(0, cos(pi / 4)), initialize=0)
     mc_expr = mc(acos((m.z)))
     self.assertAlmostEqual(mc_expr.lower(), pi / 4)
     self.assertAlmostEqual(mc_expr.upper(), pi / 2)
Example #5
0
def make2dPlot(expr, numticks=10, show_plot=False):
    mc_ccVals = [None] * (numticks + 1)
    mc_cvVals = [None] * (numticks + 1)
    aff_cc = [None] * (numticks + 1)
    aff_cv = [None] * (numticks + 1)
    fvals = [None] * (numticks + 1)
    mc_expr = mc(expr)
    x = next(identify_variables(expr))  # get the first variable
    tick_length = (x.ub - x.lb) / numticks
    xaxis = [x.lb + tick_length * n for n in range(numticks + 1)]

    x_val = value(x)  # initial value of x
    cc = mc_expr.subcc()  # Concave overestimator subgradient at x_val
    cv = mc_expr.subcv()  # Convex underestimator subgradient at x_val
    f_cc = mc_expr.concave()  # Concave overestimator value at x_val
    f_cv = mc_expr.convex()  # Convex underestimator value at x_val
    for i, x_tick in enumerate(xaxis):
        aff_cc[i] = cc[x] * (x_tick - x_val) + f_cc
        aff_cv[i] = cv[x] * (x_tick - x_val) + f_cv
        mc_expr.changePoint(x, x_tick)
        mc_ccVals[i] = mc_expr.concave()
        mc_cvVals[i] = mc_expr.convex()
        fvals[i] = value(expr)
    if show_plot:
        import matplotlib.pyplot as plt
        plt.plot(xaxis, fvals, 'r', xaxis, mc_ccVals, 'b--', xaxis,
                 mc_cvVals, 'b--', xaxis, aff_cc, 'k|', xaxis, aff_cv, 'k|')
        plt.show()
    return mc_ccVals, mc_cvVals, aff_cc, aff_cv
Example #6
0
 def test_reciprocal(self):
     m = ConcreteModel()
     m.x = Var(bounds=(1, 2), initialize=1)
     m.y = Var(bounds=(2, 3), initialize=2)
     mc_expr = mc(m.x / m.y)
     self.assertEqual(mc_expr.lower(), 1 / 3)
     self.assertEqual(mc_expr.upper(), 1)
Example #7
0
 def test_linear_expression(self):
     m = ConcreteModel()
     m.x = Var(bounds=(1, 2), initialize=1)
     with self.assertRaises(NotImplementedError):
         mc_expr = mc(quicksum([m.x, m.x], linear=True))
         self.assertEqual(mc_expr.lower(), 2)
         self.assertEqual(mc_expr.upper(), 4)
Example #8
0
 def test_powers(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 2), initialize=1)
     m.y = Var(bounds=(1e-4, 2), initialize=1)
     with self.assertRaisesRegexp(MCPP_Error, "Log with negative values in range"):
         mc(m.x ** 1.5)
     mc_expr = mc(m.y ** 1.5)
     self.assertAlmostEqual(mc_expr.lower(), 1e-4**1.5)
     self.assertAlmostEqual(mc_expr.upper(), 2**1.5)
     mc_expr = mc(m.y ** m.x)
     self.assertAlmostEqual(mc_expr.lower(), 1e-4**2)
     self.assertAlmostEqual(mc_expr.upper(), 4)
     m.z = Var(bounds=(-1, 1), initialize=0)
     mc_expr = mc(m.z ** 2)
     self.assertAlmostEqual(mc_expr.lower(), 0)
     self.assertAlmostEqual(mc_expr.upper(), 1)
Example #9
0
 def test_linear_expression(self):
     m = ConcreteModel()
     m.x = Var(bounds=(1, 2), initialize=1)
     with self.assertRaises(NotImplementedError):
         mc_expr = mc(quicksum([m.x, m.x], linear=True))
         self.assertEqual(mc_expr.lower(), 2)
         self.assertEqual(mc_expr.upper(), 4)
Example #10
0
def make2dPlot(expr, numticks=10, show_plot=False):
    mc_ccVals = [None] * (numticks + 1)
    mc_cvVals = [None] * (numticks + 1)
    aff_cc = [None] * (numticks + 1)
    aff_cv = [None] * (numticks + 1)
    fvals = [None] * (numticks + 1)
    mc_expr = mc(expr)
    x = next(identify_variables(expr))  # get the first variable
    tick_length = (x.ub - x.lb) / numticks
    xaxis = [x.lb + tick_length * n for n in range(numticks + 1)]

    x_val = value(x)  # initial value of x
    cc = mc_expr.subcc()  # Concave overestimator subgradient at x_val
    cv = mc_expr.subcv()  # Convex underestimator subgradient at x_val
    f_cc = mc_expr.concave()  # Concave overestimator value at x_val
    f_cv = mc_expr.convex()  # Convex underestimator value at x_val
    for i, x_tick in enumerate(xaxis):
        aff_cc[i] = cc[x] * (x_tick - x_val) + f_cc
        aff_cv[i] = cv[x] * (x_tick - x_val) + f_cv
        mc_expr.changePoint(x, x_tick)
        mc_ccVals[i] = mc_expr.concave()
        mc_cvVals[i] = mc_expr.convex()
        fvals[i] = value(expr)
    if show_plot:
        plt.plot(xaxis, fvals, 'r', xaxis, mc_ccVals, 'b--', xaxis,
                 mc_cvVals, 'b--', xaxis, aff_cc, 'k|', xaxis, aff_cv, 'k|')
        plt.show()
    return mc_ccVals, mc_cvVals, aff_cc, aff_cv
Example #11
0
def add_affine_cuts(nlp_result, solve_data, config):
    with time_code(solve_data.timing, "affine cut generation"):
        m = solve_data.linear_GDP
        if config.calc_disjunctive_bounds:
            with time_code(solve_data.timing, "disjunctive variable bounding"):
                TransformationFactory(
                    'contrib.compute_disj_var_bounds').apply_to(
                        m,
                        solver=config.mip_solver
                        if config.obbt_disjunctive_bounds else None)
        config.logger.info("Adding affine cuts.")
        GDPopt = m.GDPopt_utils
        counter = 0
        for var, val in zip(GDPopt.variable_list, nlp_result.var_values):
            if val is not None and not var.fixed:
                var.value = val

        for constr in constraints_in_True_disjuncts(m, config):
            # Note: this includes constraints that are deactivated in the current model (linear_GDP)

            disjunctive_var_bounds = disjunctive_bounds(constr.parent_block())

            if constr.body.polynomial_degree() in (1, 0):
                continue

            vars_in_constr = list(identify_variables(constr.body))
            if any(var.value is None for var in vars_in_constr):
                continue  # a variable has no values

            # mcpp stuff
            mc_eqn = mc(constr.body, disjunctive_var_bounds)
            # mc_eqn = mc(constr.body)
            ccSlope = mc_eqn.subcc()
            cvSlope = mc_eqn.subcv()
            ccStart = mc_eqn.concave()
            cvStart = mc_eqn.convex()
            ub_int = min(
                constr.upper,
                mc_eqn.upper()) if constr.has_ub() else mc_eqn.upper()
            lb_int = max(
                constr.lower,
                mc_eqn.lower()) if constr.has_lb() else mc_eqn.lower()

            parent_block = constr.parent_block()
            # Create a block on which to put outer approximation cuts.
            aff_utils = parent_block.component('GDPopt_aff')
            if aff_utils is None:
                aff_utils = parent_block.GDPopt_aff = Block(
                    doc="Block holding affine constraints")
                aff_utils.GDPopt_aff_cons = ConstraintList()
            aff_cuts = aff_utils.GDPopt_aff_cons
            concave_cut = sum(ccSlope[var] * (var - var.value)
                              for var in vars_in_constr) + ccStart >= lb_int
            convex_cut = sum(cvSlope[var] * (var - var.value)
                             for var in vars_in_constr) + cvStart <= ub_int
            aff_cuts.add(expr=concave_cut)
            aff_cuts.add(expr=convex_cut)
            counter += 2

        config.logger.info("Added %s affine cuts" % counter)
Example #12
0
 def test_powers(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 2), initialize=1)
     m.y = Var(bounds=(1e-4, 2), initialize=1)
     with self.assertRaisesRegex(MCPP_Error, "Log with negative values in range"):
         mc(m.x ** 1.5)
     mc_expr = mc(m.y ** 1.5)
     self.assertAlmostEqual(mc_expr.lower(), 1e-4**1.5)
     self.assertAlmostEqual(mc_expr.upper(), 2**1.5)
     mc_expr = mc(m.y ** m.x)
     self.assertAlmostEqual(mc_expr.lower(), 1e-4**2)
     self.assertAlmostEqual(mc_expr.upper(), 4)
     m.z = Var(bounds=(-1, 1), initialize=0)
     mc_expr = mc(m.z ** 2)
     self.assertAlmostEqual(mc_expr.lower(), 0)
     self.assertAlmostEqual(mc_expr.upper(), 1)
Example #13
0
 def test_reciprocal(self):
     m = ConcreteModel()
     m.x = Var(bounds=(1, 2), initialize=1)
     m.y = Var(bounds=(2, 3), initialize=2)
     mc_expr = mc(m.x / m.y)
     self.assertEqual(mc_expr.lower(), 1 / 3)
     self.assertEqual(mc_expr.upper(), 1)
Example #14
0
 def test_fixed_var(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-50, 80), initialize=3)
     m.y = Var(bounds=(0, 6), initialize=2)
     m.y.fix()
     mc_expr = mc(m.x * m.y)
     self.assertEqual(mc_expr.lower(), -100)
     self.assertEqual(mc_expr.upper(), 160)
Example #15
0
 def test_fixed_var(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-50, 80), initialize=3)
     m.y = Var(bounds=(0, 6), initialize=2)
     m.y.fix()
     mc_expr = mc(m.x * m.y)
     self.assertEqual(mc_expr.lower(), -100)
     self.assertEqual(mc_expr.upper(), 160)
Example #16
0
 def test_lmtd(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0.1, 500), initialize=33.327)
     m.y = Var(bounds=(0.1, 500), initialize=14.436)
     m.z = Var(bounds=(0, 90), initialize=22.5653)
     mc_expr = mc(m.z - (m.x * m.y * (m.x + m.y) / 2) ** (1/3))
     self.assertAlmostEqual(mc_expr.convex(), -407.95444629965016)
     self.assertAlmostEqual(mc_expr.lower(), -499.99999999999983)
Example #17
0
 def test_improved_bounds(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 100), initialize=5)
     improved_bounds = ComponentMap()
     improved_bounds[m.x] = (10, 20)
     mc_expr = mc(m.x, improved_var_bounds=improved_bounds)
     self.assertEqual(mc_expr.lower(), 10)
     self.assertEqual(mc_expr.upper(), 20)
Example #18
0
 def test_improved_bounds(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 100), initialize=5)
     improved_bounds = ComponentMap()
     improved_bounds[m.x] = (10, 20)
     mc_expr = mc(m.x, improved_var_bounds=improved_bounds)
     self.assertEqual(mc_expr.lower(), 10)
     self.assertEqual(mc_expr.upper(), 20)
Example #19
0
 def test_lmtd(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0.1, 500), initialize=33.327)
     m.y = Var(bounds=(0.1, 500), initialize=14.436)
     m.z = Var(bounds=(0, 90), initialize=22.5653)
     mc_expr = mc(m.z - (m.x * m.y * (m.x + m.y) / 2) ** (1/3))
     self.assertAlmostEqual(mc_expr.convex(), -407.95444629965016)
     self.assertAlmostEqual(mc_expr.lower(), -499.99999999999983)
Example #20
0
def add_affine_cuts(nlp_result, solve_data, config):
    with time_code(solve_data.timing, "affine cut generation"):
        m = solve_data.linear_GDP
        if config.calc_disjunctive_bounds:
            with time_code(solve_data.timing, "disjunctive variable bounding"):
                TransformationFactory('contrib.compute_disj_var_bounds').apply_to(
                    m,
                    solver=config.mip_solver if config.obbt_disjunctive_bounds else None
                )
        config.logger.info("Adding affine cuts.")
        GDPopt = m.GDPopt_utils
        counter = 0
        for var, val in zip(GDPopt.variable_list, nlp_result.var_values):
            if val is not None and not var.fixed:
                var.value = val

        for constr in constraints_in_True_disjuncts(m, config):
            # Note: this includes constraints that are deactivated in the current model (linear_GDP)

            disjunctive_var_bounds = disjunctive_bounds(constr.parent_block())

            if constr.body.polynomial_degree() in (1, 0):
                continue

            vars_in_constr = list(
                identify_variables(constr.body))
            if any(var.value is None for var in vars_in_constr):
                continue  # a variable has no values

            # mcpp stuff
            mc_eqn = mc(constr.body, disjunctive_var_bounds)
            # mc_eqn = mc(constr.body)
            ccSlope = mc_eqn.subcc()
            cvSlope = mc_eqn.subcv()
            ccStart = mc_eqn.concave()
            cvStart = mc_eqn.convex()
            ub_int = min(constr.upper, mc_eqn.upper()) if constr.has_ub() else mc_eqn.upper()
            lb_int = max(constr.lower, mc_eqn.lower()) if constr.has_lb() else mc_eqn.lower()

            parent_block = constr.parent_block()
            # Create a block on which to put outer approximation cuts.
            aff_utils = parent_block.component('GDPopt_aff')
            if aff_utils is None:
                aff_utils = parent_block.GDPopt_aff = Block(
                    doc="Block holding affine constraints")
                aff_utils.GDPopt_aff_cons = ConstraintList()
            aff_cuts = aff_utils.GDPopt_aff_cons
            concave_cut = sum(ccSlope[var] * (var - var.value)
                              for var in vars_in_constr
                              ) + ccStart >= lb_int
            convex_cut = sum(cvSlope[var] * (var - var.value)
                             for var in vars_in_constr
                             ) + cvStart <= ub_int
            aff_cuts.add(expr=concave_cut)
            aff_cuts.add(expr=convex_cut)
            counter += 2

        config.logger.info("Added %s affine cuts" % counter)
Example #21
0
 def test_fixed_var(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-50, 80), initialize=3)
     m.y = Var(bounds=(0, 6), initialize=2)
     m.y.fix()
     mc_expr = mc(m.x * m.y)
     self.assertEqual(mc_expr.lower(), -100)
     self.assertEqual(mc_expr.upper(), 160)
     self.assertEqual(
         str(mc_expr),
         "[ -1.00000e+02 :  1.60000e+02 ] [  6.00000e+00 :  6.00000e+00 ] [ ( 2.00000e+00) : ( 2.00000e+00) ]")
Example #22
0
 def test_fixed_var(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-50, 80), initialize=3)
     m.y = Var(bounds=(0, 6), initialize=2)
     m.y.fix()
     mc_expr = mc(m.x * m.y)
     self.assertEqual(mc_expr.lower(), -100)
     self.assertEqual(mc_expr.upper(), 160)
     self.assertEqual(
         str(mc_expr),
         "[ -1.00000e+02 :  1.60000e+02 ] [  6.00000e+00 :  6.00000e+00 ] [ ( 2.00000e+00) : ( 2.00000e+00) ]")
Example #23
0
 def test_powers(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 2), initialize=1)
     m.y = Var(bounds=(1e-4, 2), initialize=1)
     m.z = Var(bounds=(-1, 1), initialize=0)
     # Note: the exception raised prior to 2.1 was
     #    "Log with negative values in range"
     # This was corrected in 2.1 to
     #    "Square-root with nonpositive values in range"
     with self.assertRaisesRegex(
             MCPP_Error,
             r"(Square-root with nonpositive values in range)"
             r"|(Log with negative values in range)"):
         mc(m.z ** 1.5)
     mc_expr = mc(m.y ** 1.5)
     self.assertAlmostEqual(mc_expr.lower(), 1e-4**1.5)
     self.assertAlmostEqual(mc_expr.upper(), 2**1.5)
     mc_expr = mc(m.y ** m.x)
     self.assertAlmostEqual(mc_expr.lower(), 1e-4**2)
     self.assertAlmostEqual(mc_expr.upper(), 4)
     mc_expr = mc(m.z ** 2)
     self.assertAlmostEqual(mc_expr.lower(), 0)
     self.assertAlmostEqual(mc_expr.upper(), 1)
Example #24
0
def add_affine_cuts(nlp_result, solve_data, config):
    m = solve_data.linear_GDP
    config.logger.info("Adding affine cuts.")
    GDPopt = m.GDPopt_utils
    for var, val in zip(GDPopt.working_var_list, nlp_result.var_values):
        if val is not None and not var.fixed:
            var.value = val

    for constr in constraints_in_True_disjuncts(m, config):
        # for constr in GDPopt.working_nonlinear_constraints:

        if constr not in GDPopt.working_nonlinear_constraints:
            continue

        # if constr.body.polynomial_degree() in (1, 0):
        #     continue

        # TODO check that constraint is on active Disjunct

        vars_in_constr = list(EXPR.identify_variables(constr.body))
        if any(var.value is None for var in vars_in_constr):
            continue  # a variable has no values

        # mcpp stuff
        mc_eqn = mc(constr.body)
        ccSlope = mc_eqn.subcc()
        cvSlope = mc_eqn.subcv()
        ccStart = mc_eqn.concave()
        cvStart = mc_eqn.convex()
        ub_int = min(constr.upper,
                     mc_eqn.upper()) if constr.has_ub() else mc_eqn.upper()
        lb_int = max(constr.lower,
                     mc_eqn.lower()) if constr.has_lb() else mc_eqn.lower()

        parent_block = constr.parent_block()
        # Create a block on which to put outer approximation cuts.
        aff_utils = parent_block.component('GDPopt_aff')
        if aff_utils is None:
            aff_utils = parent_block.GDPopt_aff = Block(
                doc="Block holding affine constraints")
            aff_utils.GDPopt_aff_cons = ConstraintList()
        aff_cuts = aff_utils.GDPopt_aff_cons
        concave_cut = sum(ccSlope[var] * (var - var.value)
                          for var in vars_in_constr) + ccStart >= lb_int
        convex_cut = sum(cvSlope[var] * (var - var.value)
                         for var in vars_in_constr) + cvStart <= ub_int
        aff_cuts.add(expr=concave_cut)
        aff_cuts.add(expr=convex_cut)
Example #25
0
    def test_lmtd(self):
        m = ConcreteModel()
        m.x = Var(bounds=(0.1, 500), initialize=33.327)
        m.y = Var(bounds=(0.1, 500), initialize=14.436)
        m.z = Var(bounds=(0, 90), initialize=22.5653)
        e = m.z - (m.x * m.y * (m.x + m.y) / 2) ** (1/3)
        mc_expr = mc(e)

        for _x in [m.x.lb, m.x.ub]:
            m.x.value = _x
            mc_expr.changePoint(m.x, _x)
            for _y in [m.y.lb, m.y.ub]:
                m.y.value = _y
                mc_expr.changePoint(m.y, _y)
                for _z in [m.z.lb, m.z.ub]:
                    m.z.value = _z
                    mc_expr.changePoint(m.z, _z)
                    self.assertGreaterEqual(mc_expr.concave() + 1e-8, value(e))
                    self.assertLessEqual(mc_expr.convex() - 1e-6, value(e))

        m.x.value = m.x.lb
        m.y.value = m.y.lb
        m.z.value = m.z.lb
        mc_expr.changePoint(m.x, m.x.value)
        mc_expr.changePoint(m.y, m.y.value)
        mc_expr.changePoint(m.z, m.z.value)
        self.assertAlmostEqual(mc_expr.convex(), value(e))
        self.assertAlmostEqual(mc_expr.concave(), value(e))

        m.x.value = m.x.ub
        m.y.value = m.y.ub
        m.z.value = m.z.ub
        mc_expr.changePoint(m.x, m.x.value)
        mc_expr.changePoint(m.y, m.y.value)
        mc_expr.changePoint(m.z, m.z.value)
        self.assertAlmostEqual(mc_expr.convex(), value(e))
        self.assertAlmostEqual(mc_expr.concave(), value(e))

        self.assertAlmostEqual(mc_expr.lower(), -500)
        self.assertAlmostEqual(mc_expr.upper(), 89.9)
Example #26
0
    def add_lazy_affine_cuts(self, solve_data, config, opt):
        """
        Adds affine cuts using MCPP; add affine cuts through Cplex inherent function self.add()

        Parameters
        ----------
        solve_data: MindtPy Data Container
            data container that holds solve-instance data
        config: ConfigBlock
            contains the specific configurations for the algorithm
        opt: SolverFactory
            the mip solver
        """
        m = solve_data.mip
        config.logger.info("Adding affine cuts")
        counter = 0

        for constr in m.MindtPy_utils.constraint_list:
            if constr.body.polynomial_degree() in (1, 0):
                continue

            vars_in_constr = list(identify_variables(constr.body))
            if any(var.value is None for var in vars_in_constr):
                continue  # a variable has no values

            # mcpp stuff
            try:
                mc_eqn = mc(constr.body)
            except MCPP_Error as e:
                config.logger.debug(
                    "Skipping constraint %s due to MCPP error %s" %
                    (constr.name, str(e)))
                continue  # skip to the next constraint
            # TODO: check if the value of ccSlope and cvSlope is not Nan or inf. If so, we skip this.
            ccSlope = mc_eqn.subcc()
            cvSlope = mc_eqn.subcv()
            ccStart = mc_eqn.concave()
            cvStart = mc_eqn.convex()

            concave_cut_valid = True
            convex_cut_valid = True
            for var in vars_in_constr:
                if not var.fixed:
                    if ccSlope[var] == float('nan') or ccSlope[var] == float(
                            'inf'):
                        concave_cut_valid = False
                    if cvSlope[var] == float('nan') or cvSlope[var] == float(
                            'inf'):
                        convex_cut_valid = False
            if ccStart == float('nan') or ccStart == float('inf'):
                concave_cut_valid = False
            if cvStart == float('nan') or cvStart == float('inf'):
                convex_cut_valid = False
            # check if the value of ccSlope and cvSlope all equals zero. if so, we skip this.
            if not any(list(ccSlope.values())):
                concave_cut_valid = False
            if not any(list(cvSlope.values())):
                convex_cut_valid = False
            if (concave_cut_valid or convex_cut_valid) is False:
                continue

            ub_int = min(
                constr.upper,
                mc_eqn.upper()) if constr.has_ub() else mc_eqn.upper()
            lb_int = max(
                constr.lower,
                mc_eqn.lower()) if constr.has_lb() else mc_eqn.lower()

            parent_block = constr.parent_block()
            # Create a block on which to put outer approximation cuts.
            # TODO: create it at the beginning.
            aff_utils = parent_block.component('MindtPy_aff')
            if aff_utils is None:
                aff_utils = parent_block.MindtPy_aff = Block(
                    doc="Block holding affine constraints")
                aff_utils.MindtPy_aff_cons = ConstraintList()
            aff_cuts = aff_utils.MindtPy_aff_cons
            if concave_cut_valid:
                pyomo_concave_cut = sum(ccSlope[var] * (var - var.value)
                                        for var in vars_in_constr
                                        if not var.fixed) + ccStart
                cplex_concave_rhs = generate_standard_repn(
                    pyomo_concave_cut).constant
                cplex_concave_cut, _ = opt._get_expr_from_pyomo_expr(
                    pyomo_concave_cut)
                self.add(constraint=cplex.SparsePair(
                    ind=cplex_concave_cut.variables,
                    val=cplex_concave_cut.coefficients),
                         sense="G",
                         rhs=lb_int - cplex_concave_rhs)
                counter += 1
            if convex_cut_valid:
                pyomo_convex_cut = sum(cvSlope[var] * (var - var.value)
                                       for var in vars_in_constr
                                       if not var.fixed) + cvStart
                cplex_convex_rhs = generate_standard_repn(
                    pyomo_convex_cut).constant
                cplex_convex_cut, _ = opt._get_expr_from_pyomo_expr(
                    pyomo_convex_cut)
                self.add(constraint=cplex.SparsePair(
                    ind=cplex_convex_cut.variables,
                    val=cplex_convex_cut.coefficients),
                         sense="L",
                         rhs=ub_int - cplex_convex_rhs)
                # aff_cuts.add(expr=convex_cut)
                counter += 1

        config.logger.info("Added %s affine cuts" % counter)
Example #27
0
def add_affine_cuts(solve_data, config):
    """Adds affine cuts using MCPP.

    Parameters
    ----------
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    config : ConfigBlock
        The specific configurations for MindtPy.
    """
    with time_code(solve_data.timing, 'Affine cut generation'):
        m = solve_data.mip
        config.logger.debug('Adding affine cuts')
        counter = 0

        for constr in m.MindtPy_utils.nonlinear_constraint_list:
            vars_in_constr = list(
                identify_variables(constr.body))
            if any(var.value is None for var in vars_in_constr):
                continue  # a variable has no values

            # mcpp stuff
            try:
                mc_eqn = mc(constr.body)
            except MCPP_Error as e:
                config.logger.debug(
                    'Skipping constraint %s due to MCPP error %s' % (constr.name, str(e)))
                continue  # skip to the next constraint

            ccSlope = mc_eqn.subcc()
            cvSlope = mc_eqn.subcv()
            ccStart = mc_eqn.concave()
            cvStart = mc_eqn.convex()

            # check if the value of ccSlope and cvSlope is not Nan or inf. If so, we skip this.
            concave_cut_valid = True
            convex_cut_valid = True
            for var in vars_in_constr:
                if not var.fixed:
                    if ccSlope[var] == float('nan') or ccSlope[var] == float('inf'):
                        concave_cut_valid = False
                    if cvSlope[var] == float('nan') or cvSlope[var] == float('inf'):
                        convex_cut_valid = False
            # check if the value of ccSlope and cvSlope all equals zero. if so, we skip this.
            if not any(list(ccSlope.values())):
                concave_cut_valid = False
            if not any(list(cvSlope.values())):
                convex_cut_valid = False
            if ccStart == float('nan') or ccStart == float('inf'):
                concave_cut_valid = False
            if cvStart == float('nan') or cvStart == float('inf'):
                convex_cut_valid = False
            if not (concave_cut_valid or convex_cut_valid):
                continue

            ub_int = min(value(constr.upper), mc_eqn.upper()
                         ) if constr.has_ub() else mc_eqn.upper()
            lb_int = max(value(constr.lower), mc_eqn.lower()
                         ) if constr.has_lb() else mc_eqn.lower()

            aff_cuts = m.MindtPy_utils.cuts.aff_cuts
            if concave_cut_valid:
                concave_cut = sum(ccSlope[var] * (var - var.value)
                                  for var in vars_in_constr
                                  if not var.fixed) + ccStart >= lb_int
                aff_cuts.add(expr=concave_cut)
                counter += 1
            if convex_cut_valid:
                convex_cut = sum(cvSlope[var] * (var - var.value)
                                 for var in vars_in_constr
                                 if not var.fixed) + cvStart <= ub_int
                aff_cuts.add(expr=convex_cut)
                counter += 1

        config.logger.debug('Added %s affine cuts' % counter)
Example #28
0
def add_affine_cuts(solve_data, config):
    """
    Adds affine cuts using MCPP; modifies the model to include affine cuts

    Parameters
    ----------
    solve_data: MindtPy Data Container
        data container that holds solve-instance data
    config: ConfigBlock
        contains the specific configurations for the algorithm
    """

    m = solve_data.mip
    config.logger.info("Adding affine cuts")
    counter = 0

    for constr in m.MindtPy_utils.constraint_list:
        if constr.body.polynomial_degree() in (1, 0):
            continue

        vars_in_constr = list(identify_variables(constr.body))
        if any(var.value is None for var in vars_in_constr):
            continue  # a variable has no values

        # mcpp stuff
        try:
            mc_eqn = mc(constr.body)
        except MCPP_Error as e:
            config.logger.debug("Skipping constraint %s due to MCPP error %s" %
                                (constr.name, str(e)))
            continue  # skip to the next constraint

        ccSlope = mc_eqn.subcc()
        cvSlope = mc_eqn.subcv()
        ccStart = mc_eqn.concave()
        cvStart = mc_eqn.convex()

        # check if the value of ccSlope and cvSlope is not Nan or inf. If so, we skip this.
        concave_cut_valid = True
        convex_cut_valid = True
        for var in vars_in_constr:
            if not var.fixed:
                if ccSlope[var] == float('nan') or ccSlope[var] == float(
                        'inf'):
                    concave_cut_valid = False
                if cvSlope[var] == float('nan') or cvSlope[var] == float(
                        'inf'):
                    convex_cut_valid = False
        # check if the value of ccSlope and cvSlope all equals zero. if so, we skip this.
        if not any(list(ccSlope.values())):
            concave_cut_valid = False
        if not any(list(cvSlope.values())):
            convex_cut_valid = False
        if ccStart == float('nan') or ccStart == float('inf'):
            concave_cut_valid = False
        if cvStart == float('nan') or cvStart == float('inf'):
            convex_cut_valid = False
        if (concave_cut_valid or convex_cut_valid) is False:
            continue

        ub_int = min(constr.upper,
                     mc_eqn.upper()) if constr.has_ub() else mc_eqn.upper()
        lb_int = max(constr.lower,
                     mc_eqn.lower()) if constr.has_lb() else mc_eqn.lower()

        parent_block = constr.parent_block()
        # Create a block on which to put outer approximation cuts.
        # TODO: create it at the beginning.
        aff_utils = parent_block.component('MindtPy_aff')
        if aff_utils is None:
            aff_utils = parent_block.MindtPy_aff = Block(
                doc="Block holding affine constraints")
            aff_utils.MindtPy_aff_cons = ConstraintList()
        aff_cuts = aff_utils.MindtPy_aff_cons
        if concave_cut_valid:
            concave_cut = sum(ccSlope[var] * (var - var.value)
                              for var in vars_in_constr
                              if not var.fixed) + ccStart >= lb_int
            aff_cuts.add(expr=concave_cut)
            counter += 1
        if convex_cut_valid:
            convex_cut = sum(cvSlope[var] * (var - var.value)
                             for var in vars_in_constr
                             if not var.fixed) + cvStart <= ub_int
            aff_cuts.add(expr=convex_cut)
            counter += 1

    config.logger.info("Added %s affine cuts" % counter)
Example #29
0
 def test_outofbounds(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-1, 5), initialize=2)
     with self.assertRaisesRegexp(MCPP_Error, '.*Log with negative values in range'):
         mc(log(m.x))
Example #30
0
def make3dPlot(expr, numticks=30, show_plot=False):
    ccSurf = [None] * ((numticks + 1)**2)
    cvSurf = [None] * ((numticks + 1)**2)
    fvals = [None] * ((numticks + 1)**2)
    xaxis2d = [None] * ((numticks + 1)**2)
    yaxis2d = [None] * ((numticks + 1)**2)
    ccAffine = [None] * ((numticks + 1)**2)
    cvAffine = [None] * ((numticks + 1)**2)

    eqn = mc(expr)
    vars = identify_variables(expr)
    x = next(vars)
    y = next(vars)
    x_tick_length = (x.ub - x.lb) / numticks
    y_tick_length = (y.ub - y.lb) / numticks
    xaxis = [x.lb + x_tick_length * n for n in range(numticks + 1)]
    yaxis = [y.lb + y_tick_length * n for n in range(numticks + 1)]

    # Making the affine tangent planes
    ccSlope = eqn.subcc()
    cvSlope = eqn.subcv()
    x_val = value(x)
    y_val = value(y)
    f_cc = eqn.concave()
    f_cv = eqn.convex()

    # To Visualize Concave Affine Plane for different points
    for i, x_tick in enumerate(xaxis):
        eqn.changePoint(x, x_tick)
        for j, y_tick in enumerate(yaxis):
            ccAffine[i + (numticks + 1) * j] = (
                ccSlope[x] * (x_tick - x_val) +
                ccSlope[y] * (y_tick - y_val) + f_cc)
            cvAffine[i + (numticks + 1) * j] = (
                cvSlope[x] * (x_tick - x_val) +
                cvSlope[y] * (y_tick - y_val) + f_cv)
            xaxis2d[i + (numticks + 1) * j] = x_tick
            yaxis2d[i + (numticks + 1) * j] = y_tick
            eqn.changePoint(y, y_tick)
            ccSurf[i + (numticks + 1) * j] = eqn.concave()
            cvSurf[i + (numticks + 1) * j] = eqn.convex()
            fvals[i + (numticks + 1) * j] = value(expr)

    if show_plot:
        import matplotlib.pyplot as plt
        from mpl_toolkits.mplot3d import Axes3D
        assert Axes3D  # silence pyflakes

        # Plotting Solutions in 3D
        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1, projection='3d')
        ax.scatter(xaxis2d, yaxis2d, cvSurf, color='b')
        ax.scatter(xaxis2d, yaxis2d, fvals, color='r')
        ax.scatter(xaxis2d, yaxis2d, ccSurf, color='b')

        # To Visualize Concave Affine Plane for different points
        ax.scatter(xaxis2d, yaxis2d, cvAffine, color='k')

        # Create a better view
        ax.view_init(10, 270)
        plt.show()

    return ccSurf, cvSurf, ccAffine, cvAffine
Example #31
0
 def test_nonpyomo_numeric(self):
     mc_expr = mc(-2)
     self.assertEqual(mc_expr.lower(), -2)
     self.assertEqual(mc_expr.upper(), -2)
Example #32
0
 def test_abs(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-1, 1), initialize=0)
     mc_expr = mc(abs((m.x)))
     self.assertEqual(mc_expr.lower(), 0)
     self.assertEqual(mc_expr.upper(), 1)
Example #33
0
def make3dPlot(expr, numticks=30, show_plot=False):
    ccSurf = [None] * ((numticks + 1)**2)
    cvSurf = [None] * ((numticks + 1)**2)
    fvals = [None] * ((numticks + 1)**2)
    xaxis2d = [None] * ((numticks + 1)**2)
    yaxis2d = [None] * ((numticks + 1)**2)
    ccAffine = [None] * ((numticks + 1)**2)
    cvAffine = [None] * ((numticks + 1)**2)

    eqn = mc(expr)
    vars = identify_variables(expr)
    x = next(vars)
    y = next(vars)
    x_tick_length = (x.ub - x.lb) / numticks
    y_tick_length = (y.ub - y.lb) / numticks
    xaxis = [x.lb + x_tick_length * n for n in range(numticks + 1)]
    yaxis = [y.lb + y_tick_length * n for n in range(numticks + 1)]

    # Making the affine tangent planes
    ccSlope = eqn.subcc()
    cvSlope = eqn.subcv()
    x_val = value(x)
    y_val = value(y)
    f_cc = eqn.concave()
    f_cv = eqn.convex()

    # To Visualize Concave Affine Plane for different points
    for i, x_tick in enumerate(xaxis):
        eqn.changePoint(x, x_tick)
        for j, y_tick in enumerate(yaxis):
            ccAffine[i + (numticks + 1) * j] = (
                ccSlope[x] * (x_tick - x_val) +
                ccSlope[y] * (y_tick - y_val) + f_cc)
            cvAffine[i + (numticks + 1) * j] = (
                cvSlope[x] * (x_tick - x_val) +
                cvSlope[y] * (y_tick - y_val) + f_cv)
            xaxis2d[i + (numticks + 1) * j] = x_tick
            yaxis2d[i + (numticks + 1) * j] = y_tick
            eqn.changePoint(y, y_tick)
            ccSurf[i + (numticks + 1) * j] = eqn.concave()
            cvSurf[i + (numticks + 1) * j] = eqn.convex()
            fvals[i + (numticks + 1) * j] = value(expr)

    if show_plot:
        from mpl_toolkits.mplot3d import Axes3D
        assert Axes3D  # silence pyflakes

        # Plotting Solutions in 3D
        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1, projection='3d')
        ax.scatter(xaxis2d, yaxis2d, cvSurf, color='b')
        ax.scatter(xaxis2d, yaxis2d, fvals, color='r')
        ax.scatter(xaxis2d, yaxis2d, ccSurf, color='b')

        # To Visualize Concave Affine Plane for different points
        ax.scatter(xaxis2d, yaxis2d, cvAffine, color='k')

        # Create a better view
        ax.view_init(10, 270)
        plt.show()

    return ccSurf, cvSurf, ccAffine, cvAffine
Example #34
0
 def test_outofbounds(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-1, 5), initialize=2)
     with self.assertRaisesRegex(MCPP_Error, '.*Log with negative values in range'):
         mc(log(m.x))
Example #35
0
 def test_abs(self):
     m = ConcreteModel()
     m.x = Var(bounds=(-1, 1), initialize=0)
     mc_expr = mc(abs((m.x)))
     self.assertEqual(mc_expr.lower(), 0)
     self.assertEqual(mc_expr.upper(), 1)
Example #36
0
    def add_lazy_affine_cuts(self, solve_data, config, opt):
        """Adds affine cuts using MCPP.

        Add affine cuts through Cplex inherent function self.add().

        Parameters
        ----------
        solve_data : MindtPySolveData
            Data container that holds solve-instance data.
        config : ConfigBlock
            The specific configurations for MindtPy.
        opt : SolverFactory
            The cplex_persistent solver.
        """
        with time_code(solve_data.timing, 'Affine cut generation'):
            m = solve_data.mip
            config.logger.debug('Adding affine cuts')
            counter = 0

            for constr in m.MindtPy_utils.nonlinear_constraint_list:

                vars_in_constr = list(identify_variables(constr.body))
                if any(var.value is None for var in vars_in_constr):
                    continue  # a variable has no values

                # mcpp stuff
                try:
                    mc_eqn = mc(constr.body)
                except MCPP_Error as e:
                    config.logger.debug(
                        'Skipping constraint %s due to MCPP error %s' %
                        (constr.name, str(e)))
                    continue  # skip to the next constraint
                # TODO: check if the value of ccSlope and cvSlope is not Nan or inf. If so, we skip this.
                ccSlope = mc_eqn.subcc()
                cvSlope = mc_eqn.subcv()
                ccStart = mc_eqn.concave()
                cvStart = mc_eqn.convex()

                concave_cut_valid = True
                convex_cut_valid = True
                for var in vars_in_constr:
                    if not var.fixed:
                        if ccSlope[var] == float(
                                'nan') or ccSlope[var] == float('inf'):
                            concave_cut_valid = False
                        if cvSlope[var] == float(
                                'nan') or cvSlope[var] == float('inf'):
                            convex_cut_valid = False
                if ccStart == float('nan') or ccStart == float('inf'):
                    concave_cut_valid = False
                if cvStart == float('nan') or cvStart == float('inf'):
                    convex_cut_valid = False
                # check if the value of ccSlope and cvSlope all equals zero. if so, we skip this.
                if not any(ccSlope.values()):
                    concave_cut_valid = False
                if not any(cvSlope.values()):
                    convex_cut_valid = False
                if not (concave_cut_valid or convex_cut_valid):
                    continue

                ub_int = min(
                    value(constr.upper),
                    mc_eqn.upper()) if constr.has_ub() else mc_eqn.upper()
                lb_int = max(
                    value(constr.lower),
                    mc_eqn.lower()) if constr.has_lb() else mc_eqn.lower()

                if concave_cut_valid:
                    pyomo_concave_cut = sum(ccSlope[var] * (var - var.value)
                                            for var in vars_in_constr
                                            if not var.fixed) + ccStart
                    cplex_concave_rhs = generate_standard_repn(
                        pyomo_concave_cut).constant
                    cplex_concave_cut, _ = opt._get_expr_from_pyomo_expr(
                        pyomo_concave_cut)
                    self.add(constraint=cplex.SparsePair(
                        ind=cplex_concave_cut.variables,
                        val=cplex_concave_cut.coefficients),
                             sense='G',
                             rhs=lb_int - cplex_concave_rhs)
                    counter += 1
                if convex_cut_valid:
                    pyomo_convex_cut = sum(cvSlope[var] * (var - var.value)
                                           for var in vars_in_constr
                                           if not var.fixed) + cvStart
                    cplex_convex_rhs = generate_standard_repn(
                        pyomo_convex_cut).constant
                    cplex_convex_cut, _ = opt._get_expr_from_pyomo_expr(
                        pyomo_convex_cut)
                    self.add(constraint=cplex.SparsePair(
                        ind=cplex_convex_cut.variables,
                        val=cplex_convex_cut.coefficients),
                             sense='L',
                             rhs=ub_int - cplex_convex_rhs)
                    counter += 1

            config.logger.info('Added %s affine cuts' % counter)
Example #37
0
 def test_nonpyomo_numeric(self):
     mc_expr = mc(-2)
     self.assertEqual(mc_expr.lower(), -2)
     self.assertEqual(mc_expr.upper(), -2)