Пример #1
0
    def test_pyomo_external_model(self):
        m = pyo.ConcreteModel()
        m.Pin = pyo.Var(initialize=100, bounds=(0,None))
        m.c1 = pyo.Var(initialize=1.0, bounds=(0,None))
        m.c2 = pyo.Var(initialize=1.0, bounds=(0,None))
        m.F = pyo.Var(initialize=10, bounds=(0,None))

        m.P1 = pyo.Var()
        m.P2 = pyo.Var()

        m.F_con = pyo.Constraint(expr = m.F == 10)
        m.Pin_con = pyo.Constraint(expr = m.Pin == 100)

        # simple parameter estimation test
        m.obj = pyo.Objective(expr= (m.P1 - 90)**2 + (m.P2 - 40)**2)

        cyipopt_problem = \
            PyomoExternalCyIpoptProblem(m,
                                        PressureDropModel(),
                                        [m.Pin, m.c1, m.c2, m.F],
                                        [m.P1, m.P2]
                                        )

        # check that the dummy variable is initialized
        expected_dummy_var_value = pyo.value(m.Pin) + pyo.value(m.c1) + pyo.value(m.c2) + pyo.value(m.F) \
            + 0 + 0
            # + pyo.value(m.P1) + pyo.value(m.P2) # not initialized - therefore should use zero
        self.assertAlmostEqual(pyo.value(m._dummy_variable_CyIpoptPyomoExNLP), expected_dummy_var_value)

        # solve the problem
        solver = CyIpoptSolver(cyipopt_problem, {'hessian_approximation':'limited-memory'})
        x, info = solver.solve(tee=False)
        cyipopt_problem.load_x_into_pyomo(x)
        self.assertAlmostEqual(pyo.value(m.c1), 0.1, places=5)
        self.assertAlmostEqual(pyo.value(m.c2), 0.5, places=5)
Пример #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)
Пример #3
0
    def test_composite_nlp(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])

        scenarios = dict()
        coupling_vars = dict()
        n_scenarios = 2
        np.random.seed(seed=985739465)
        bs = [b, b + 0.001]

        for i in range(n_scenarios):
            instance = create_model3(G, A, bs[i], c)
            nlp = PyomoNLP(instance)
            scenario_name = "s{}".format(i)
            scenarios[scenario_name] = nlp
            coupling_vars[scenario_name] = [nlp.variable_idx(instance.x[0])]

        nlp = TwoStageStochasticNLP(scenarios, coupling_vars)

        solver = CyIpoptSolver(nlp)
        x, info = solver.solve(tee=False)
        x_sol = np.array([
            2.00003846, -0.99996154, 0.99996154, 2.00003846, -0.99996154,
            1.00096154, 2.00003846
        ])

        self.assertTrue(np.allclose(x, x_sol, rtol=1e-4))
        self.assertAlmostEqual(nlp.objective(x), -6.99899, 3)
Пример #4
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)
Пример #5
0
 def test_model2(self):
     model = create_model2()
     nlp = PyomoNLP(model)
     solver = CyIpoptSolver(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))
     self.assertAlmostEqual(nlp.objective(x), -31.000000057167462, 3)
     self.assertTrue(np.allclose(info['mult_g'], y_sol, rtol=1e-4))
Пример #6
0
 def test_model1(self):
     model = create_model1()
     nlp = PyomoNLP(model)
     solver = CyIpoptSolver(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))
     self.assertAlmostEqual(nlp.objective(x), -428.6362455416348)
     self.assertTrue(np.allclose(info['mult_g'], y_sol, rtol=1e-4))
    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)
Пример #8
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))
Пример #9
0
    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(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))
        self.assertAlmostEqual(nlp.objective(x), -3.5, 3)
        self.assertTrue(np.allclose(info['mult_g'], y_sol, rtol=1e-4))
Пример #10
0
    def test_pyomo_external_model_ndarray_scaling(self):
        m = pyo.ConcreteModel()
        m.Pin = pyo.Var(initialize=100, bounds=(0, None))
        m.c1 = pyo.Var(initialize=1.0, bounds=(0, None))
        m.c2 = pyo.Var(initialize=1.0, bounds=(0, None))
        m.F = pyo.Var(initialize=10, bounds=(0, None))

        m.P1 = pyo.Var()
        m.P2 = pyo.Var()

        m.F_con = pyo.Constraint(expr=m.F == 10)
        m.Pin_con = pyo.Constraint(expr=m.Pin == 100)

        # simple parameter estimation test
        m.obj = pyo.Objective(expr=(m.P1 - 90)**2 + (m.P2 - 40)**2)

        # set scaling parameters for the pyomo variables and constraints
        m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)
        m.scaling_factor[m.obj] = 0.1  # scale the objective
        m.scaling_factor[m.Pin] = 2.0  # scale the variable
        m.scaling_factor[m.c1] = 3.0  # scale the variable
        m.scaling_factor[m.c2] = 4.0  # scale the variable
        m.scaling_factor[m.F] = 5.0  # scale the variable
        m.scaling_factor[m.P1] = 6.0  # scale the variable
        m.scaling_factor[m.P2] = 7.0  # scale the variable
        m.scaling_factor[m.F_con] = 8.0  # scale the pyomo constraint
        m.scaling_factor[m.Pin_con] = 9.0  # scale the pyomo constraint

        # test that this all works with ndarray input as well
        cyipopt_problem = \
            PyomoExternalCyIpoptProblem(pyomo_model=m,
                                        ex_input_output_model=PressureDropModel(),
                                        inputs=[m.Pin, m.c1, m.c2, m.F],
                                        outputs=[m.P1, m.P2],
                                        outputs_eqn_scaling=np.asarray([10.0, 11.0], dtype=np.float64)
                                        )

        # solve the problem
        options = {
            'hessian_approximation': 'limited-memory',
            'nlp_scaling_method': 'user-scaling',
            'output_file': '_cyipopt-pyomo-ext-scaling-ndarray.log',
            'file_print_level': 10,
            'max_iter': 0
        }
        solver = CyIpoptSolver(cyipopt_problem, options=options)
        x, info = solver.solve(tee=False)

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

        self.assertIn('nlp_scaling_method = user-scaling', solver_trace)
        self.assertIn('output_file = _cyipopt-pyomo-ext-scaling-ndarray.log',
                      solver_trace)
        self.assertIn('objective scaling factor = 0.1', 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 7 elements:',
                      solver_trace)
        self.assertIn('x scaling vector[    1]= 6.0000000000000000e+00',
                      solver_trace)
        self.assertIn('x scaling vector[    2]= 7.0000000000000000e+00',
                      solver_trace)
        self.assertIn('x scaling vector[    3]= 2.0000000000000000e+00',
                      solver_trace)
        self.assertIn('x scaling vector[    4]= 3.0000000000000000e+00',
                      solver_trace)
        self.assertIn('x scaling vector[    5]= 4.0000000000000000e+00',
                      solver_trace)
        self.assertIn('x scaling vector[    6]= 5.0000000000000000e+00',
                      solver_trace)
        self.assertIn('x scaling vector[    7]= 1.0000000000000000e+00',
                      solver_trace)
        self.assertIn('DenseVector "c scaling vector" with 5 elements:',
                      solver_trace)
        self.assertIn('c scaling vector[    1]= 8.0000000000000000e+00',
                      solver_trace)
        self.assertIn('c scaling vector[    2]= 9.0000000000000000e+00',
                      solver_trace)
        self.assertIn('c scaling vector[    3]= 1.0000000000000000e+00',
                      solver_trace)
        self.assertIn('c scaling vector[    4]= 1.0000000000000000e+01',
                      solver_trace)
        self.assertIn('c scaling vector[    5]= 1.1000000000000000e+01',
                      solver_trace)
Пример #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