def test_solve_gsl_function(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") model = ConcreteModel() model.z_func = ExternalFunction(library=DLL, function="gsl_sf_gamma") model.x = Var(initialize=3, bounds=(1e-5,None)) model.o = Objective(expr=model.z_func(model.x)) opt = SolverFactory('ipopt') res = opt.solve(model, tee=True) self.assertAlmostEqual(value(model.o), 0.885603194411, 7)
def _external_model(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") m = ConcreteModel() m.hypot = ExternalFunction(library=DLL, function="gsl_hypot") m.p = Param(initialize=1, mutable=True) m.x = Var(initialize=3, bounds=(1e-5,None)) m.y = Var(initialize=3, bounds=(0,None)) m.z = Var(initialize=1) m.o = Objective( expr=m.z**2 * m.hypot(m.p*m.x, m.p+m.y)**2) self.assertAlmostEqual(value(m.o), 25.0, 7) return m
def test_eval_gsl_function(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") model = ConcreteModel() model.gamma = ExternalFunction( library=DLL, function="gsl_sf_gamma") model.bessel = ExternalFunction( library=DLL, function="gsl_sf_bessel_Jnu") model.x = Var(initialize=3, bounds=(1e-5,None)) model.o = Objective(expr=model.gamma(model.x)) self.assertAlmostEqual(value(model.o), 2.0, 7) f = model.bessel.evaluate((0.5, 2.0,)) self.assertAlmostEqual(f, 0.5130161365618272, 7)
def test_eval_fgh_gsl_function(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") model = ConcreteModel() model.gamma = ExternalFunction( library=DLL, function="gsl_sf_gamma") model.bessel = ExternalFunction( library=DLL, function="gsl_sf_bessel_Jnu") f,g,h = model.gamma.evaluate_fgh((2.0,)) self.assertAlmostEqual(f, 1.0, 7) self.assertListsAlmostEqual(g, [0.422784335098467], 7) self.assertListsAlmostEqual(h, [0.8236806608528794], 7) f,g,h = model.bessel.evaluate_fgh((2.5, 2.0,), fixed=[1,0]) self.assertAlmostEqual(f, 0.223924531469, 7) self.assertListsAlmostEqual(g, [0.0, 0.21138811435101745], 7) self.assertListsAlmostEqual(h, [0.0, 0.0, 0.02026349177575621], 7)
def test_eval_fgh_gsl_function(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") model = ConcreteModel() model.gamma = ExternalFunction(library=DLL, function="gsl_sf_gamma") model.bessel = ExternalFunction(library=DLL, function="gsl_sf_bessel_Jnu") f, g, h = model.gamma.evaluate_fgh((2.0, )) self.assertAlmostEqual(f, 1.0, 7) self.assertAlmostEqual(g, [0.422784335098467], 7) self.assertAlmostEqual(h, [0.8236806608528794], 7) f, g, h = model.bessel.evaluate_fgh(( 2.5, 2.0, ), fixed=[1, 0]) self.assertAlmostEqual(f, 0.223924531469, 7) self.assertAlmostEqual(g, [0.0, 0.21138811435101745], 7) self.assertAlmostEqual(h, [0.0, 0.0, 0.02026349177575621], 7)
def test_external_expression_constant(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") m = ConcreteModel() m.y = Var(initialize=4, bounds=(0, None)) m.hypot = ExternalFunction(library=DLL, function="gsl_hypot") m.o = Objective(expr=m.hypot(3, m.y)) self.assertAlmostEqual(value(m.o), 5.0, 7) baseline_fname, test_fname = self._get_fnames() self._cleanup(test_fname) m.write(test_fname, format='nl', io_options={'symbolic_solver_labels': True}) self.assertTrue(cmp(test_fname, baseline_fname), msg="Files %s and %s differ" % (test_fname, baseline_fname)) self._cleanup(test_fname)
def test_clone_gsl_function(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") m = ConcreteModel() m.z_func = ExternalFunction(library=DLL, function="gsl_sf_gamma") self.assertIsInstance(m.z_func, AMPLExternalFunction) m.x = Var(initialize=3, bounds=(1e-5, None)) m.o = Objective(expr=m.z_func(m.x)) opt = SolverFactory('ipopt') # Test a simple clone... model2 = m.clone() res = opt.solve(model2, tee=True) self.assertAlmostEqual(value(model2.o), 0.885603194411, 7) # Trigger the library to be loaded. This tests that the CDLL # objects that are created when the SO/DLL are loaded do not # interfere with cloning the model. self.assertAlmostEqual(value(m.o), 2) model3 = m.clone() res = opt.solve(model3, tee=True) self.assertAlmostEqual(value(model3.o), 0.885603194411, 7)
class TestSubsystemBlock(unittest.TestCase): def test_square_subsystem(self): m = _make_simple_model() cons = [m.con2, m.con3] vars = [m.v1, m.v2] # With m.v3 and m.v4 fixed, m.con2 and m.con3 form a square subsystem block = create_subsystem_block(cons, vars) self.assertEqual(len(block.vars), 2) self.assertEqual(len(block.cons), 2) self.assertEqual(len(block.input_vars), 2) self.assertEqual(len([v for v in block.component_data_objects(pyo.Var) if not v.fixed]), 4) block.input_vars.fix() self.assertEqual(len([v for v in block.component_data_objects(pyo.Var) if not v.fixed]), 2) self.assertIs(block.cons[0], m.con2) self.assertIs(block.cons[1], m.con3) self.assertIs(block.vars[0], m.v1) self.assertIs(block.vars[1], m.v2) self.assertIs(block.input_vars[0], m.v4) self.assertIs(block.input_vars[1], m.v3) # Make sure block is not part of the original model's tree. We # don't want to alter the user's model at all. self.assertIsNot(block.model(), m) # Components on the block are references to components on the # original model for comp in block.component_objects((pyo.Var, pyo.Constraint)): self.assertTrue(comp.is_reference()) for data in comp.values(): self.assertIs(data.model(), m) def test_subsystem_inputs_only(self): m = _make_simple_model() cons = [m.con2, m.con3] block = create_subsystem_block(cons) self.assertEqual(len(block.vars), 0) self.assertEqual(len(block.input_vars), 4) self.assertEqual(len(block.cons), 2) self.assertEqual(len([v for v in block.component_data_objects(pyo.Var) if not v.fixed]), 4) block.input_vars.fix() self.assertEqual(len([v for v in block.component_data_objects(pyo.Var) if not v.fixed]), 0) var_set = ComponentSet([m.v1, m.v2, m.v3, m.v4]) self.assertIs(block.cons[0], m.con2) self.assertIs(block.cons[1], m.con3) self.assertIn(block.input_vars[0], var_set) self.assertIn(block.input_vars[1], var_set) self.assertIn(block.input_vars[2], var_set) self.assertIn(block.input_vars[3], var_set) # Make sure block is not part of the original model's tree. We # don't want to alter the user's model at all. self.assertIsNot(block.model(), m) # Components on the block are references to components on the # original model for comp in block.component_objects((pyo.Var, pyo.Constraint)): self.assertTrue(comp.is_reference()) for data in comp.values(): self.assertIs(data.model(), m) @unittest.skipUnless(pyo.SolverFactory("ipopt").available(), "Ipopt is not available") def test_solve_subsystem(self): # This is a test of this function's intended use. We extract a # subsystem then solve it without altering the rest of the model. m = _make_simple_model() ipopt = pyo.SolverFactory("ipopt") m.v5 = pyo.Var(initialize=1.0) m.c4 = pyo.Constraint(expr=m.v5 == 5.0) cons = [m.con2, m.con3] vars = [m.v1, m.v2] block = create_subsystem_block(cons, vars) m.v3.fix(1.0) m.v4.fix(2.0) # Initialize to avoid converging infeasible due to bad pivots m.v1.set_value(1.0) m.v2.set_value(1.0) ipopt.solve(block) # Have solved model to expected values self.assertAlmostEqual(m.v1.value, pyo.sqrt(7.0), delta=1e-8) self.assertAlmostEqual(m.v2.value, pyo.sqrt(4.0-pyo.sqrt(7.0)), delta=1e-8) # Rest of model has not changed self.assertEqual(m.v5.value, 1.0) def test_generate_subsystems_without_fixed_var(self): m = _make_simple_model() subs = [ ([m.con1], [m.v1, m.v4]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1, m.v4], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): with TemporarySubsystemManager(to_fix=inputs): self.assertIs(block.model(), block) var_set = ComponentSet(subs[i][1]) con_set = ComponentSet(subs[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(block.input_vars)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) # Test that we have properly unfixed variables self.assertFalse(any(var.fixed for var in m.component_data_objects(pyo.Var))) def test_generate_subsystems_with_exception(self): m = _make_simple_model() subs = [ ([m.con1], [m.v1, m.v4]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1, m.v4], ] with self.assertRaises(RuntimeError): for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): with TemporarySubsystemManager(to_fix=inputs): self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) if i == 1: raise RuntimeError() # Test that we have properly unfixed variables self.assertFalse(any(var.fixed for var in m.component_data_objects(pyo.Var))) def test_generate_subsystems_with_fixed_var(self): m = _make_simple_model() m.v4.fix() subs = [ ([m.con1], [m.v1]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): inputs = list(block.input_vars.values()) with TemporarySubsystemManager(to_fix=inputs): self.assertIs(block.model(), block) var_set = ComponentSet(subs[i][1]) con_set = ComponentSet(subs[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(inputs)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) # Test that we have properly unfixed variables, except variables # that were already fixed. self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed) def test_generate_subsystems_include_fixed_var(self): m = _make_simple_model() m.v4.fix() subsystems = [ ([m.con1], [m.v1]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3, m.v4], [m.v1, m.v4], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks( subsystems, include_fixed=True, )): with TemporarySubsystemManager(to_fix=inputs): self.assertIs(block.model(), block) var_set = ComponentSet(subsystems[i][1]) con_set = ComponentSet(subsystems[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(block.input_vars)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertTrue(all(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed) def test_generate_subsystems_dont_fix_inputs(self): m = _make_simple_model() subs = [ ([m.con1], [m.v1]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3, m.v4], [m.v1, m.v4], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): self.assertIs(block.model(), block) var_set = ComponentSet(subs[i][1]) con_set = ComponentSet(subs[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(inputs)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertFalse(any(var.fixed for var in inputs)) self.assertFalse(any(var.fixed for var in block.vars[:])) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertFalse(m.v4.fixed) def test_generate_dont_fix_inputs_with_fixed_var(self): m = _make_simple_model() m.v4.fix() subs = [ ([m.con1], [m.v1]), ([m.con2, m.con3], [m.v2, m.v3]), ] other_vars = [ [m.v2, m.v3], [m.v1], ] for i, (block, inputs) in enumerate(generate_subsystem_blocks(subs)): self.assertIs(block.model(), block) var_set = ComponentSet(subs[i][1]) con_set = ComponentSet(subs[i][0]) input_set = ComponentSet(other_vars[i]) self.assertEqual(len(var_set), len(block.vars)) self.assertEqual(len(con_set), len(block.cons)) self.assertEqual(len(input_set), len(inputs)) self.assertTrue(all(var in var_set for var in block.vars[:])) self.assertTrue(all(con in con_set for con in block.cons[:])) self.assertTrue(all(var in input_set for var in inputs)) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed) self.assertFalse(m.v1.fixed) self.assertFalse(m.v2.fixed) self.assertFalse(m.v3.fixed) self.assertTrue(m.v4.fixed) def _make_model_with_external_functions(self): m = pyo.ConcreteModel() gsl = find_GSL() m.bessel = pyo.ExternalFunction( library=gsl, function="gsl_sf_bessel_J0" ) m.fermi = pyo.ExternalFunction( library=gsl, function="gsl_sf_fermi_dirac_m1" ) m.v1 = pyo.Var(initialize=1.0) m.v2 = pyo.Var(initialize=2.0) m.v3 = pyo.Var(initialize=3.0) m.con1 = pyo.Constraint(expr=m.v1 == 0.5) m.con2 = pyo.Constraint(expr=2*m.fermi(m.v1) + m.v2**2 - m.v3 == 1.0) m.con3 = pyo.Constraint( expr=m.bessel(m.v1) - m.bessel(m.v2) + m.v3**2 == 2.0 ) return m @unittest.skipUnless(find_GSL(), "Could not find the AMPL GSL library") def test_identify_external_functions(self): m = self._make_model_with_external_functions() m._con = pyo.Constraint(expr=2*m.fermi(m.bessel(m.v1**2) + 0.1) == 1.0) gsl = find_GSL() fcns = list(identify_external_functions(m.con2.expr)) self.assertEqual(len(fcns), 1) self.assertEqual(fcns[0]._fcn._library, gsl) self.assertEqual(fcns[0]._fcn._function, "gsl_sf_fermi_dirac_m1") fcns = list(identify_external_functions(m.con3.expr)) fcn_data = set((fcn._fcn._library, fcn._fcn._function) for fcn in fcns) self.assertEqual(len(fcns), 2) pred_fcn_data = {(gsl, "gsl_sf_bessel_J0")} self.assertEqual(fcn_data, pred_fcn_data) fcns = list(identify_external_functions(m._con.expr)) fcn_data = set((fcn._fcn._library, fcn._fcn._function) for fcn in fcns) self.assertEqual(len(fcns), 2) pred_fcn_data = { (gsl, "gsl_sf_bessel_J0"), (gsl, "gsl_sf_fermi_dirac_m1"), } self.assertEqual(fcn_data, pred_fcn_data) def _solve_ef_model_with_ipopt(self): m = self._make_model_with_external_functions() ipopt = pyo.SolverFactory("ipopt") ipopt.solve(m) return m @unittest.skipUnless(find_GSL(), "Could not find the AMPL GSL library") @unittest.skipUnless( pyo.SolverFactory("ipopt").available(), "ipopt is not available" ) def test_with_external_function(self): m = self._make_model_with_external_functions() subsystem = ([m.con2, m.con3], [m.v2, m.v3]) m.v1.set_value(0.5) block = create_subsystem_block(*subsystem) ipopt = pyo.SolverFactory("ipopt") with TemporarySubsystemManager(to_fix=list(block.input_vars.values())): ipopt.solve(block) # Correct values obtained by solving with Ipopt directly # in another script. self.assertEqual(m.v1.value, 0.5) self.assertFalse(m.v1.fixed) self.assertAlmostEqual(m.v2.value, 1.04816, delta=1e-5) self.assertAlmostEqual(m.v3.value, 1.34356, delta=1e-5) # Result obtained by solving the full system m_full = self._solve_ef_model_with_ipopt() self.assertAlmostEqual(m.v1.value, m_full.v1.value) self.assertAlmostEqual(m.v2.value, m_full.v2.value) self.assertAlmostEqual(m.v3.value, m_full.v3.value) @unittest.skipUnless(find_GSL(), "Could not find the AMPL GSL library") def test_external_function_with_potential_name_collision(self): m = self._make_model_with_external_functions() m.b = pyo.Block() m.b._gsl_sf_bessel_J0 = pyo.Var() m.b.con = pyo.Constraint( expr=m.b._gsl_sf_bessel_J0 == m.bessel(m.v1) ) add_local_external_functions(m.b) self.assertTrue(isinstance(m.b._gsl_sf_bessel_J0, pyo.Var)) ex_fcns = list(m.b.component_objects(pyo.ExternalFunction)) self.assertEqual(len(ex_fcns), 1) fcn = ex_fcns[0] self.assertEqual(fcn._function, "gsl_sf_bessel_J0")
def test_eval_fgh_gsl_function(self): DLL = find_GSL() if not DLL: self.skipTest("Could not find the amplgsl.dll library") model = ConcreteModel() model.gamma = ExternalFunction(library=DLL, function="gsl_sf_gamma") model.beta = ExternalFunction(library=DLL, function="gsl_sf_beta") model.bessel = ExternalFunction(library=DLL, function="gsl_sf_bessel_Jnu") f, g, h = model.gamma.evaluate_fgh((2.0, )) self.assertAlmostEqual(f, 1.0, 7) self.assertListsAlmostEqual(g, [0.422784335098467], 7) self.assertListsAlmostEqual(h, [0.8236806608528794], 7) f, g, h = model.beta.evaluate_fgh(( 2.5, 2.0, ), fixed=[1, 1]) self.assertAlmostEqual(f, 0.11428571428571432, 7) self.assertListsAlmostEqual(g, [0.0, 0.0], 7) self.assertListsAlmostEqual(h, [0.0, 0.0, 0.0], 7) f, g, h = model.beta.evaluate_fgh(( 2.5, 2.0, ), fixed=[0, 1]) self.assertAlmostEqual(f, 0.11428571428571432, 7) self.assertListsAlmostEqual(g, [-0.07836734693877555, 0.0], 7) self.assertListsAlmostEqual(h, [0.08135276967930034, 0.0, 0.0], 7) f, g, h = model.beta.evaluate_fgh(( 2.5, 2.0, )) self.assertAlmostEqual(f, 0.11428571428571432, 7) self.assertListsAlmostEqual( g, [-0.07836734693877555, -0.11040989614412142], 7) self.assertListsAlmostEqual( h, [0.08135276967930034, 0.0472839170086535, 0.15194654464270113], 7) f, g, h = model.beta.evaluate_fgh(( 2.5, 2.0, ), fgh=1) self.assertAlmostEqual(f, 0.11428571428571432, 7) self.assertListsAlmostEqual( g, [-0.07836734693877555, -0.11040989614412142], 7) self.assertIsNone(h) f, g, h = model.beta.evaluate_fgh(( 2.5, 2.0, ), fgh=0) self.assertAlmostEqual(f, 0.11428571428571432, 7) self.assertIsNone(g) self.assertIsNone(h) f, g, h = model.bessel.evaluate_fgh(( 2.5, 2.0, ), fixed=[1, 0]) self.assertAlmostEqual(f, 0.223924531469, 7) self.assertListsAlmostEqual(g, [0.0, 0.21138811435101745], 7) self.assertListsAlmostEqual(h, [0.0, 0.0, 0.02026349177575621], 7) # Note: Not all AMPL-GSL functions honor the fixed flag # (notably, gamma and bessel do not as of 12/2021). We will # test that our interface corrects that f, g, h = model.gamma.evaluate_fgh((2.0, ), fixed=[1]) self.assertAlmostEqual(f, 1.0, 7) self.assertListsAlmostEqual(g, [0.0], 7) self.assertListsAlmostEqual(h, [0.0], 7) f, g, h = model.bessel.evaluate_fgh(( 2.5, 2.0, ), fixed=[1, 1]) self.assertAlmostEqual(f, 0.223924531469, 7) self.assertListsAlmostEqual(g, [0.0, 0.0], 7) self.assertListsAlmostEqual(h, [0.0, 0.0, 0.0], 7)