Source code for tests.interface.test_sas_interface

#!/usr/bin/env python
# encoding: utf-8
#
# Copyright SAS Institute
#
#  Licensed under the Apache License, Version 2.0 (the License);
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#

from inspect import cleandoc
import unittest
import os
import sasoptpy as so
import saspy


current_dir = os.path.dirname(os.path.abspath(__file__))


[docs]class TestSASInterface(unittest.TestCase): """ Unit tests for the SAS interface """ @classmethod def setUpClass(cls): cls.conn = None try: cls.conn = None if os.name == 'nt': cls.conn = saspy.SASsession(cfgname='winlocal') else: cfg_file = os.path.join( current_dir, '../examples/saspy_config.py') cls.conn = saspy.SASsession(cfgfile=cfg_file) print('Connected to SAS') except TypeError: raise unittest.SkipTest('Environment variable may not be defined') @classmethod def tearDownClass(cls): if cls.conn is not None: cls.conn.endsas() cls.conn = None def setUp(self): so.reset() def test_long_names(self): if TestSASInterface.conn is None: self.skipTest('SAS session is not available') vs = 10 m = so.Model(name='test_long_name', session=TestSASInterface.conn) x = m.add_variables( vs, name='averylongvariablenamethatdoesnotwork', ub=2, lb=0) c = m.add_constraint( so.expr_sum(i * x[i] for i in range(vs)) <= 1, name='c') o = m.set_objective( so.expr_sum(x[i] for i in range(vs)), sense=so.MAX, name='obj') def raise_runtime(): m.solve() self.assertRaises(RuntimeError, raise_runtime) m.solve(limit_names=True) m.get_solution() self.assertEqual(x[0].get_value(), 2) m.set_objective(x[0], sense=so.MIN, name='obj2') m.solve(limit_names=True, submit=False) self.assertEqual(x[0].get_value(), 2) def test_long_lines(self): if TestSASInterface.conn is None: self.skipTest('SAS session is not available') vs = 2000 m = so.Model(name='test_long_line', session=TestSASInterface.conn) x = m.add_variables(vs, name='averylongvariablename', ub=2, lb=0) c = m.add_constraint( so.expr_sum(i * x[i] for i in range(vs)) <= 1, name='c') o = m.set_objective(x[0], sense=so.MAX, name='obj') m.solve(wrap_lines=True) self.assertEqual(x[0].get_value(), 2) def test_mps_on_sas(self): if TestSASInterface.conn is None: self.skipTest('SAS session is not available') m = so.Model(name='test_mps_on_sas', session=TestSASInterface.conn) x = m.add_variables(10, name='x', lb=0) m.add_constraints((x[i] >= i for i in range(10)), name='c') m.set_objective( so.expr_sum(x[i] for i in range(10)), sense=so.MIN, name='obj') m.solve(mps=True, verbose=True) self.assertEqual(x[2].get_value(), 2) def test_workspace_post_value(self): if TestSASInterface.conn is None: self.skipTest('SAS session is not available') with so.Workspace('test_ws_var_value', session=TestSASInterface.conn) as w: x = so.Variable(name='x') c = so.Constraint(x <= 5, name='c') o = so.Objective(x, sense=so.MAX, name='obj') so.actions.solve() self.assertEqual(so.to_optmodel(w), cleandoc(''' proc optmodel; var x; con c : x <= 5; max obj = x; solve; quit;''')) w.submit() self.assertEqual(x.get_value(), 5) def test_forced_optmodel(self): if not TestSASInterface.conn: self.skipTest('No session is available') # Forced to OPTMODEL due abstract elements m = so.Model(name='test_forced_optmodel', session=TestSASInterface.conn) S = so.Set(name='S') m.include(S) x = m.add_variable(name='x', ub=1) m.set_objective(2*x, sense=so.MAX, name='obj') def warn_abstract(): response = m.solve(mps=True, submit=False) self.assertIn('set S;', response) self.assertWarns(UserWarning, warn_abstract) # Uploaded MPS Table m.drop(S) response = m.solve(mps=True, submit=False) # Forced to OPTMODEL due nonlinearity m.set_objective(x**2, sense=so.MAX, name='obj2') def warn_nonlinear(): response = m.solve(mps=True, submit=False) self.assertIn('var x', response) self.assertWarns(UserWarning, warn_nonlinear) # Forced to give error def force_decomp(): m.solve(mps=True, options={'decomp': 'USER'}) self.assertRaises(RuntimeError, force_decomp) # No objective m.solve(mps=True, verbose=True, name='no_obj') def test_postprocess_optmodel_string(self): if TestSASInterface.conn is None: self.skipTest('SAS session is not available') with so.Workspace('w', session=TestSASInterface.conn) as w: x = so.Variable(name='x') o = so.Objective((x-1)**2, sense=so.MIN, name='obj') so.actions.solve() w.submit(limit_names=True, wrap_lines=True) self.assertEqual(x.get_value(), 1) def test_optmodel_error(self): if TestSASInterface.conn is None: self.skipTest('SAS session is not available') with so.Workspace('w', session=TestSASInterface.conn) as w: so.abstract.LiteralStatement('abc') def produce_error(): w.submit(verbose=True) self.assertRaises(RuntimeError, produce_error)