def test_cyipopt_nlp(self):
     m = self.make_model()
     scaling_factors = [1e-4, 1e4]
     m.epm.set_equality_constraint_scaling_factors(scaling_factors)
     nlp = PyomoNLPWithGreyBoxBlocks(m)
     cyipopt_nlp = CyIpoptNLP(nlp)
     obj_scaling, x_scaling, g_scaling = cyipopt_nlp.scaling_factors()
     np.testing.assert_array_equal(scaling_factors, g_scaling)
Exemple #2
0
 def test_options(self):
     model = create_model1()
     nlp = PyomoNLP(model)
     solver = CyIpoptSolver(CyIpoptNLP(nlp), options={'max_iter': 1})
     x, info = solver.solve(tee=False)
     nlp.set_primals(x)
     self.assertAlmostEqual(nlp.evaluate_objective(), -5.0879028e+02, places=5)
Exemple #3
0
    def test_model1_with_scaling(self):
        m = create_model1()
        m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)
        m.scaling_factor[m.o] = 1e-6 # scale the objective
        m.scaling_factor[m.c] = 2.0  # scale the equality constraint
        m.scaling_factor[m.d] = 3.0  # scale the inequality constraint
        m.scaling_factor[m.x[1]] = 4.0  # scale one of the x variables

        cynlp = CyIpoptNLP(PyomoNLP(m))
        options={'nlp_scaling_method': 'user-scaling',
                 'output_file': '_cyipopt-scaling.log',
                 'file_print_level':10,
                 'max_iter': 0}
        solver = CyIpoptSolver(cynlp, options=options)
        x, info = solver.solve()

        with open('_cyipopt-scaling.log', 'r') as fd:
            solver_trace = fd.read()
        os.remove('_cyipopt-scaling.log')

        # check for the following strings in the log and then delete the log
        self.assertIn('nlp_scaling_method = user-scaling', solver_trace)
        self.assertIn('output_file = _cyipopt-scaling.log', solver_trace)
        self.assertIn('objective scaling factor = 1e-06', solver_trace)
        self.assertIn('x scaling provided', solver_trace)
        self.assertIn('c scaling provided', solver_trace)
        self.assertIn('d scaling provided', solver_trace)
        self.assertIn('DenseVector "x scaling vector" with 3 elements:', solver_trace)
        self.assertIn('x scaling vector[    1]= 1.0000000000000000e+00', solver_trace)
        self.assertIn('x scaling vector[    2]= 1.0000000000000000e+00', solver_trace)
        self.assertIn('x scaling vector[    3]= 4.0000000000000000e+00', solver_trace)
        self.assertIn('DenseVector "c scaling vector" with 1 elements:', solver_trace)
        self.assertIn('c scaling vector[    1]= 2.0000000000000000e+00', solver_trace)
        self.assertIn('DenseVector "d scaling vector" with 1 elements:', solver_trace)
        self.assertIn('d scaling vector[    1]= 3.0000000000000000e+00', solver_trace)
    def test_cyipopt_callback(self):
        # Use a callback to check that the reported infeasibility is
        # due to the scaled equality constraints.
        # Note that the scaled infeasibility is not what we see if we
        # call solve with tee=True, as by default the displayed infeasibility
        # is unscaled. Luckily, we can still access the scaled infeasibility
        # with a callback.
        m = self.make_model()
        scaling_factors = [1e-4, 1e4]
        m.epm.set_equality_constraint_scaling_factors(scaling_factors)
        nlp = PyomoNLPWithGreyBoxBlocks(m)

        def callback(
            local_nlp,
            alg_mod,
            iter_count,
            obj_value,
            inf_pr,
            inf_du,
            mu,
            d_norm,
            regularization_size,
            alpha_du,
            alpha_pr,
            ls_trials,
        ):
            primals = tuple(local_nlp.get_primals())
            # I happen to know the order of the primals here
            u, v, x, y = primals

            # Calculate the scaled residuals I expect
            con_3_resid = scaling_factors[0] * abs(
                self.con_3_body(x, y, u, v) - self.con_3_rhs())
            con_4_resid = scaling_factors[1] * abs(
                self.con_4_body(x, y, u, v) - self.con_4_rhs())
            pred_inf_pr = max(con_3_resid, con_4_resid)

            # Make sure Ipopt is using the scaled constraints internally
            self.assertAlmostEqual(inf_pr, pred_inf_pr)

        cyipopt_nlp = CyIpoptNLP(
            nlp,
            intermediate_callback=callback,
        )
        x0 = nlp.get_primals()
        cyipopt = CyIpoptSolver(
            cyipopt_nlp,
            options={
                "max_iter": 0,
                "nlp_scaling_method": "user-scaling",
            },
        )
        cyipopt.solve(x0=x0)
Exemple #5
0
 def test_model2(self):
     model = create_model2()
     nlp = PyomoNLP(model)
     solver = CyIpoptSolver(CyIpoptNLP(nlp))
     x, info = solver.solve(tee=False)
     x_sol = np.array([3.0, 1.99997807])
     y_sol = np.array([0.00017543])
     self.assertTrue(np.allclose(x, x_sol, rtol=1e-4))
     nlp.set_primals(x)
     nlp.set_duals(y_sol)
     self.assertAlmostEqual(nlp.evaluate_objective(), -31.000000057167462, places=5)
     self.assertTrue(np.allclose(info['mult_g'], y_sol, rtol=1e-4))
Exemple #6
0
 def test_model1(self):
     model = create_model1()
     nlp = PyomoNLP(model)
     solver = CyIpoptSolver(CyIpoptNLP(nlp))
     x, info = solver.solve(tee=False)
     x_sol = np.array([3.85958688, 4.67936007, 3.10358931])
     y_sol = np.array([-1.0, 53.90357665])
     self.assertTrue(np.allclose(x, x_sol, rtol=1e-4))
     nlp.set_primals(x)
     nlp.set_duals(y_sol)
     self.assertAlmostEqual(nlp.evaluate_objective(), -428.6362455416348, places=5)
     self.assertTrue(np.allclose(info['mult_g'], y_sol, rtol=1e-4))
    def test_model3(self):
        G = np.array([[6, 2, 1], [2, 5, 2], [1, 2, 4]])
        A = np.array([[1, 0, 1], [0, 1, 1]])
        b = np.array([3, 0])
        c = np.array([-8, -3, -3])

        model = create_model3(G, A, b, c)
        nlp = PyomoNLP(model)
        solver = CyIpoptSolver(CyIpoptNLP(nlp))
        x, info = solver.solve(tee=False)
        x_sol = np.array([2.0, -1.0, 1.0])
        y_sol = np.array([-3., 2.])
        self.assertTrue(np.allclose(x, x_sol, rtol=1e-4))
        nlp.set_primals(x)
        nlp.set_duals(y_sol)
        self.assertAlmostEqual(nlp.evaluate_objective(), -3.5, places=5)
        self.assertTrue(np.allclose(info['mult_g'], y_sol, rtol=1e-4))
    def test_model1(self):
        model = create_model1()
        nlp = PyomoNLP(model)
        cynlp = CyIpoptNLP(nlp)

        # test x_init
        expected_xinit = np.asarray([4.0, 4.0, 4.0], dtype=np.float64)
        xinit = cynlp.x_init()
        self.assertTrue(np.array_equal(xinit, expected_xinit))

        # test x_lb
        expected_xlb = list()
        for v in nlp.get_pyomo_variables():
            if v.lb == None:
                expected_xlb.append(-np.inf)
            else:
                expected_xlb.append(v.lb)
        expected_xlb = np.asarray(expected_xlb)
        xlb = cynlp.x_lb()
        self.assertTrue(np.array_equal(xlb, expected_xlb))

        # test x_ub
        expected_xub = list()
        for v in nlp.get_pyomo_variables():
            if v.ub == None:
                expected_xub.append(np.inf)
            else:
                expected_xub.append(v.ub)
        expected_xub = np.asarray(expected_xub)
        xub = cynlp.x_ub()
        self.assertTrue(np.array_equal(xub, expected_xub))

        # test g_lb
        expected_glb = np.asarray([-np.inf, 0.0], dtype=np.float64)
        glb = cynlp.g_lb()
        self.assertTrue(np.array_equal(glb, expected_glb))

        # test g_ub
        expected_gub = np.asarray([18, 0.0], dtype=np.float64)
        gub = cynlp.g_ub()
        print(expected_gub)
        print(gub)
        self.assertTrue(np.array_equal(gub, expected_gub))

        x = cynlp.x_init()
        # test objective
        self.assertEqual(cynlp.objective(x), -504)
        # test gradient
        expected = np.asarray([-576, 8, 64], dtype=np.float64)
        self.assertTrue(np.allclose(expected, cynlp.gradient(x)))
        # test constraints
        expected = np.asarray([20, -5], dtype=np.float64)
        constraints = cynlp.constraints(x)
        self.assertTrue(np.allclose(expected, constraints)) 
        
        # test jacobian
        expected = np.asarray([[8.0, 0, 1.0],[0.0, 8.0, 1.0]])
        spexpected = spa.coo_matrix(expected).todense()
        rows, cols = cynlp.jacobianstructure()
        values = cynlp.jacobian(x)
        jac = spa.coo_matrix((values, (rows,cols)), shape=(len(constraints), len(x))).todense()
        self.assertTrue(np.allclose(spexpected, jac))

        # test hessian
        y = constraints.copy()
        y.fill(1.0)
        rows, cols = cynlp.hessianstructure()
        values = cynlp.hessian(x, y, obj_factor=1.0)
        hess_lower = spa.coo_matrix((values, (rows,cols)), shape=(len(x), len(x))).todense()
        expected_hess_lower = np.asarray([[-286.0, 0.0, 0.0], [0.0, 4.0, 0.0], [-144.0, 0.0, 192.0]], dtype=np.float64)
        self.assertTrue(np.allclose(expected_hess_lower, hess_lower))
Exemple #9
0
    def test_model1_CyIpoptNLP_scaling(self):
        m = create_model1()
        m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)

        m.scaling_factor[m.o] = 1e-6  # scale the objective
        m.scaling_factor[m.c] = 2.0  # scale the equality constraint
        m.scaling_factor[m.d] = 3.0  # scale the inequality constraint
        m.scaling_factor[m.x[1]] = 4.0  # scale one of the x variables

        cynlp = CyIpoptNLP(PyomoNLP(m))
        obj_scaling, x_scaling, g_scaling = cynlp.scaling_factors()
        self.assertTrue(obj_scaling == 1e-6)
        self.assertTrue(len(x_scaling) == 3)
        # vars are in order x[2], x[3], x[1]
        self.assertTrue(x_scaling[0] == 1.0)
        self.assertTrue(x_scaling[1] == 1.0)
        self.assertTrue(x_scaling[2] == 4.0)
        self.assertTrue(len(g_scaling) == 2)
        # assuming the order is d then c
        self.assertTrue(g_scaling[0] == 3.0)
        self.assertTrue(g_scaling[1] == 2.0)

        # test missing obj
        m = create_model1()
        m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)

        #m.scaling_factor[m.o] = 1e-6 # scale the objective
        m.scaling_factor[m.c] = 2.0  # scale the equality constraint
        m.scaling_factor[m.d] = 3.0  # scale the inequality constraint
        m.scaling_factor[m.x[1]] = 4.0  # scale the x variable

        cynlp = CyIpoptNLP(PyomoNLP(m))
        obj_scaling, x_scaling, g_scaling = cynlp.scaling_factors()
        self.assertTrue(obj_scaling == 1.0)
        self.assertTrue(len(x_scaling) == 3)
        # vars are in order x[2], x[3], x[1]
        self.assertTrue(x_scaling[0] == 1.0)
        self.assertTrue(x_scaling[1] == 1.0)
        self.assertTrue(x_scaling[2] == 4.0)
        self.assertTrue(len(g_scaling) == 2)
        # assuming the order is d then c
        self.assertTrue(g_scaling[0] == 3.0)
        self.assertTrue(g_scaling[1] == 2.0)

        # test missing var
        m = create_model1()
        m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)

        m.scaling_factor[m.o] = 1e-6  # scale the objective
        m.scaling_factor[m.c] = 2.0  # scale the equality constraint
        m.scaling_factor[m.d] = 3.0  # scale the inequality constraint
        #m.scaling_factor[m.x] = 4.0  # scale the x variable

        cynlp = CyIpoptNLP(PyomoNLP(m))
        obj_scaling, x_scaling, g_scaling = cynlp.scaling_factors()
        self.assertTrue(obj_scaling == 1e-6)
        self.assertTrue(len(x_scaling) == 3)
        # vars are in order x[2], x[3], x[1]
        self.assertTrue(x_scaling[0] == 1.0)
        self.assertTrue(x_scaling[1] == 1.0)
        self.assertTrue(x_scaling[2] == 1.0)
        self.assertTrue(len(g_scaling) == 2)
        # assuming the order is d then c
        self.assertTrue(g_scaling[0] == 3.0)
        self.assertTrue(g_scaling[1] == 2.0)

        # test missing c
        m = create_model1()
        m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)

        m.scaling_factor[m.o] = 1e-6  # scale the objective
        #m.scaling_factor[m.c] = 2.0  # scale the equality constraint
        m.scaling_factor[m.d] = 3.0  # scale the inequality constraint
        m.scaling_factor[m.x[1]] = 4.0  # scale the x variable

        cynlp = CyIpoptNLP(PyomoNLP(m))
        obj_scaling, x_scaling, g_scaling = cynlp.scaling_factors()
        self.assertTrue(obj_scaling == 1e-6)
        self.assertTrue(len(x_scaling) == 3)
        # vars are in order x[2], x[3], x[1]
        self.assertTrue(x_scaling[0] == 1.0)
        self.assertTrue(x_scaling[1] == 1.0)
        self.assertTrue(x_scaling[2] == 4.0)
        self.assertTrue(len(g_scaling) == 2)
        # assuming the order is d then c
        self.assertTrue(g_scaling[0] == 3.0)
        self.assertTrue(g_scaling[1] == 1.0)

        # test missing all
        m = create_model1()
        #m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)
        #m.scaling_factor[m.o] = 1e-6 # scale the objective
        #m.scaling_factor[m.c] = 2.0  # scale the equality constraint
        #m.scaling_factor[m.d] = 3.0  # scale the inequality constraint
        #m.scaling_factor[m.x] = 4.0  # scale the x variable

        cynlp = CyIpoptNLP(PyomoNLP(m))
        obj_scaling, x_scaling, g_scaling = cynlp.scaling_factors()
        self.assertTrue(obj_scaling is None)
        self.assertTrue(x_scaling is None)
        self.assertTrue(g_scaling is None)
Exemple #10
0
 def test_model1_CyIpoptNLP(self):
     model = create_model1()
     nlp = PyomoNLP(model)
     cynlp = CyIpoptNLP(nlp)
     self._check_model1(nlp, cynlp)
Exemple #11
0
    def __init__(
        self,
        input_vars,
        external_vars,
        residual_cons,
        external_cons,
        use_cyipopt=None,
        solver=None,
    ):
        """
        Arguments:
        ----------
        input_vars: list
            List of variables sent to this system by the outer solver
        external_vars: list
            List of variables that are solved for internally by this system
        residual_cons: list
            List of equality constraints whose residuals are exposed to
            the outer solver
        external_cons: list
            List of equality constraints used to solve for the external
            variables
        use_cyipopt: bool
            Whether to use CyIpopt to solve strongly connected components of
            the implicit function that have dimension greater than one.
        solver: Pyomo solver object
            Used to solve strongly connected components of the implicit function
            that have dimension greater than one. Only used if use_cyipopt
            is False.

        """
        if use_cyipopt is None:
            use_cyipopt = cyipopt_available
        if use_cyipopt and not cyipopt_available:
            raise RuntimeError(
                "Constructing an ExternalPyomoModel with CyIpopt unavailable. "
                "Please set the use_cyipopt argument to False.")
        if solver is not None and use_cyipopt:
            raise RuntimeError(
                "Constructing an ExternalPyomoModel with a solver specified "
                "and use_cyipopt set to True. Please set use_cyipopt to False "
                "to use the desired solver.")
        elif solver is None and not use_cyipopt:
            solver = SolverFactory("ipopt")
        # If use_cyipopt is True, this solver is None and will not be used.
        self._solver = solver
        self._use_cyipopt = use_cyipopt

        # We only need this block to construct the NLP, which wouldn't
        # be necessary if we could compute Hessians of Pyomo constraints.
        self._block = create_subsystem_block(
            residual_cons + external_cons,
            input_vars + external_vars,
        )
        self._block._obj = Objective(expr=0.0)
        self._nlp = PyomoNLP(self._block)

        self._scc_list = list(
            generate_strongly_connected_components(external_cons,
                                                   variables=external_vars))

        if use_cyipopt:
            # Using CyIpopt allows us to solve inner problems without
            # costly rewriting of the nl file. It requires quite a bit
            # of preprocessing, however, to construct the ProjectedNLP
            # for each block of the decomposition.

            # Get "vector-valued" SCCs, those of dimension > 0.
            # We will solve these with a direct IPOPT interface, which requires
            # some preprocessing.
            self._vector_scc_list = [(scc, inputs)
                                     for scc, inputs in self._scc_list
                                     if len(scc.vars) > 1]

            # Need a dummy objective to create an NLP
            for scc, inputs in self._vector_scc_list:
                scc._obj = Objective(expr=0.0)

                # I need scaling_factor so Pyomo NLPs I create from these blocks
                # don't break when ProjectedNLP calls get_primals_scaling
                scc.scaling_factor = Suffix(direction=Suffix.EXPORT)
                # HACK: scaling_factor just needs to be nonempty.
                scc.scaling_factor[scc._obj] = 1.0

            # These are the "original NLPs" that will be projected
            self._vector_scc_nlps = [
                PyomoNLP(scc) for scc, inputs in self._vector_scc_list
            ]
            self._vector_scc_var_names = [[
                var.name for var in scc.vars.values()
            ] for scc, inputs in self._vector_scc_list]
            self._vector_proj_nlps = [
                ProjectedNLP(nlp, names) for nlp, names in zip(
                    self._vector_scc_nlps, self._vector_scc_var_names)
            ]

            # We will solve the ProjectedNLPs rather than the original NLPs
            self._cyipopt_nlps = [
                CyIpoptNLP(nlp) for nlp in self._vector_proj_nlps
            ]
            self._cyipopt_solvers = [
                CyIpoptSolver(nlp) for nlp in self._cyipopt_nlps
            ]
            self._vector_scc_input_coords = [
                nlp.get_primal_indices(inputs) for nlp, (scc, inputs) in zip(
                    self._vector_scc_nlps, self._vector_scc_list)
            ]

        assert len(external_vars) == len(external_cons)

        self.input_vars = input_vars
        self.external_vars = external_vars
        self.residual_cons = residual_cons
        self.external_cons = external_cons

        self.residual_con_multipliers = [None for _ in residual_cons]
        self.residual_scaling_factors = None