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)
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)
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)
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))
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))
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)
def test_model1_CyIpoptNLP(self): model = create_model1() nlp = PyomoNLP(model) cynlp = CyIpoptNLP(nlp) self._check_model1(nlp, cynlp)
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