diff --git a/pyomo/solvers/plugins/solvers/mosek_direct.py b/pyomo/solvers/plugins/solvers/mosek_direct.py index 00e4d1d97e2..32ea0c99879 100644 --- a/pyomo/solvers/plugins/solvers/mosek_direct.py +++ b/pyomo/solvers/plugins/solvers/mosek_direct.py @@ -163,21 +163,28 @@ def _process_stream(msg): for key, option in self.options.items(): try: param = key.split('.') - if param[0] == 'mosek': - param.pop(0) - param = getattr(mosek, param[0])(param[1]) - if 'sparam' in key.split('.'): - self._solver_model.putstrparam(param, option) - elif 'dparam' in key.split('.'): - self._solver_model.putdouparam(param, option) - elif 'iparam' in key.split('.'): - if isinstance(option, str): - option = option.split('.') - if option[0] == 'mosek': - option.pop('mosek') - option = getattr(mosek, option[0])(option[1]) - else: + if key == param[0]: + self._solver_model.putparam(key, option) + else: + if param[0] == 'mosek': + param.pop(0) + assert ( + len(param) == 2 + ), "unrecognized MOSEK parameter name '{}'".format(key) + param = getattr(mosek, param[0])(param[1]) + if 'sparam.' in key: + self._solver_model.putstrparam(param, option) + elif 'dparam.' in key: + self._solver_model.putdouparam(param, option) + elif 'iparam.' in key: + if isinstance(option, str): + option = option.split('.') + if option[0] == 'mosek': + option.pop(0) + option = getattr(mosek, option[0])(option[1]) self._solver_model.putintparam(param, option) + else: + raise ValueError(f"unrecognized MOSEK parameter name '{key}'") except (TypeError, AttributeError): raise try: diff --git a/pyomo/solvers/tests/checks/test_MOSEKDirect.py b/pyomo/solvers/tests/checks/test_MOSEKDirect.py index 345c7690f7b..79888effb2e 100644 --- a/pyomo/solvers/tests/checks/test_MOSEKDirect.py +++ b/pyomo/solvers/tests/checks/test_MOSEKDirect.py @@ -313,6 +313,62 @@ def test_conic_duals(self): results.Solution.constraint['x11']['Dual'][i], check[i], 5 ) + def test_solver_parameters(self): + import mosek + + solver = pyo.SolverFactory('mosek_direct') + model = self._test_model() + solver.solve( + model, + options={ + 'dparam.optimizer_max_time': 1.0, + 'iparam.intpnt_solve_form': mosek.solveform.dual, + 'mosek.iparam.intpnt_max_iterations': 10, + 'MSK_DPAR_INTPNT_CO_TOL_REL_GAP': '1.0e-7', + 'MSK_IPAR_PRESOLVE_USE': '0', + 'sparam.param_comment_sign': '##', + }, + ) + # Check if iparams were set correctly + self.assertEqual( + solver._solver_model.getintparam(mosek.iparam.intpnt_solve_form), + mosek.solveform.dual, + ) + self.assertEqual( + solver._solver_model.getintparam(mosek.iparam.intpnt_max_iterations), 10 + ) + self.assertEqual( + solver._solver_model.getintparam(mosek.iparam.presolve_use), + mosek.presolvemode.off, + ) + # Check if dparams were set correctly + self.assertEqual( + solver._solver_model.getdouparam(mosek.dparam.optimizer_max_time), 1.0 + ) + self.assertEqual( + solver._solver_model.getdouparam(mosek.dparam.intpnt_co_tol_rel_gap), 1.0e-7 + ) + # Check if sparam is set correctly + self.assertEqual( + solver._solver_model.getstrparam(mosek.sparam.param_comment_sign)[1], '##' + ) + # Check for TypeErrors + with self.assertRaises(TypeError) as typeCheck: + solver.solve(model, options={'mosek.dparam.intpnt_co_tol_rel_gap': '1.4'}) + with self.assertRaises(TypeError) as typeCheck: + solver.solve(model, options={'iparam.log': 1.2}) + # Check for AttributeError + with self.assertRaises(AttributeError) as assertCheck: + solver.solve(model, options={'wrong.name': '1'}) + with self.assertRaises(AttributeError) as typeCheck: + solver.solve(model, options={'mosek.iparam.log': 'mosek.wrong.input'}) + # Check for wrong parameter name (but valid MOSEK attribute) + with self.assertRaises(ValueError) as typeCheck: + solver.solve(model, options={'mosek.mark.up': 'wrong.val'}) + # Check for parameter names with wrong length + with self.assertRaises(AssertionError) as typeCheck: + solver.solve(model, options={'mosek.iparam.log.level': 10}) + if __name__ == "__main__": unittest.main()