Handling Data¶
sasoptpy can work with native Python types and pandas objects for all
data operations.
Among pandas object types, sasoptpy works with pandas.DataFrame
and pandas.Series
objects to construct and manipulate model components.
Indices¶
Methods like Model.add_variables()
can use native Python object
types such as list and range as variable and constraint indices.
You can also use pandas.Index
objects as indices as well.
List¶
In [1]: m = so.Model(name='demo')
NOTE: Initialized model demo.
In [2]: SEASONS = ['Fall', 'Winter', 'Spring', 'Summer']
In [3]: prod_lb = {'Fall': 100, 'Winter': 200, 'Spring': 100, 'Summer': 400}
In [4]: production = m.add_variables(SEASONS, lb=prod_lb, name='production')
In [5]: print(production)
Variable Group (production) [
[Fall: production[Fall]]
[Winter: production[Winter]]
[Spring: production[Spring]]
[Summer: production[Summer]]
]
In [6]: print(repr(production['Summer']))
sasoptpy.Variable(name='production[Summer]', lb=400, vartype='CONT')
If a list is used as the index set, associated fields such as
lb, and ub should be accessible by using the index keys. Accepted types are dict
and pandas.Series
.
Range¶
In [7]: link = m.add_variables(range(3), range(2), vartype=so.BIN, name='link')
In [8]: print(link)
Variable Group (link) [
[(0, 0): link[0, 0]]
[(0, 1): link[0, 1]]
[(1, 0): link[1, 0]]
[(1, 1): link[1, 1]]
[(2, 0): link[2, 0]]
[(2, 1): link[2, 1]]
]
In [9]: print(repr(link[2, 1]))
sasoptpy.Variable(name='link[2,1]', lb=0, ub=1, vartype='BIN')
pandas.Index¶
In [10]: import pandas as pd
In [11]: p_data = [[3, 5, 9],
....: [0, -1, 14],
....: [5, 6, 20]]
....:
In [12]: df = pd.DataFrame(p_data, columns=['c1', 'col_lb', 'col_ub'])
In [13]: x = m.add_variables(df.index, lb=df['c1'], vartype=so.INT, name='x')
In [14]: print(x)
Variable Group (x) [
[0: x[0]]
[1: x[1]]
[2: x[2]]
]
In [15]: df2 = df.set_index([['r1', 'r2', 'r3']])
In [16]: y = m.add_variables(df2.index, lb=df2['col_lb'], ub=df2['col_ub'], name='y')
In [17]: print(y)
Variable Group (y) [
[r1: y[r1]]
[r2: y[r2]]
[r3: y[r3]]
]
In [18]: print(repr(y['r1']))
sasoptpy.Variable(name='y[r1]', lb=5, ub=9, vartype='CONT')
Set¶
sasoptpy can work with data on the server and generate abstract
expressions. For this purpose, you can use Set
objects to represent
PROC OPTMODEL sets.
In [19]: m2 = so.Model(name='m2')
NOTE: Initialized model m2.
In [20]: I = m2.add_set(name='I')
In [21]: u = m2.add_variables(I, name='u')
In [22]: print(I, u)
I Variable Group (u) [
]
See Workflows for more information about working with server-side models.
Data¶
sasoptpy can work with both client-side and server-side data. Here are some options to load data into the optimization models.
pandas DataFrame¶
pandas.DataFrame
is the preferred object type for passing data into
sasoptpy models.
In [23]: data = [
....: ['clock', 8, 4, 3],
....: ['mug', 10, 6, 5],
....: ['headphone', 15, 7, 2],
....: ['book', 20, 12, 10],
....: ['pen', 1, 1, 15]
....: ]
....:
In [24]: df = pd.DataFrame(data, columns=['item', 'value', 'weight', 'limit']).set_index(['item'])
In [25]: get = so.VariableGroup(df.index, ub=df['limit'], name='get')
In [26]: print(get)
Variable Group (get) [
[clock: get[clock]]
[mug: get[mug]]
[headphone: get[headphone]]
[book: get[book]]
[pen: get[pen]]
]
Dictionaries¶
You can use lists and dictionaries in expressions and when you create variables.
In [27]: items = ['clock', 'mug', 'headphone', 'book', 'pen']
In [28]: limits = {'clock': 3, 'mug': 5, 'headphone': 2, 'book': 10, 'pen': 15}
In [29]: get2 = so.VariableGroup(items, ub=limits, name='get2')
In [30]: print(get2)
Variable Group (get2) [
[clock: get2[clock]]
[mug: get2[mug]]
[headphone: get2[headphone]]
[book: get2[book]]
[pen: get2[pen]]
]
CASTable¶
When data are available on the server-side, you can pass a reference to the object.
Using swat.cas.table.CASTable
and abstract data requires SAS Viya 3.4 or later.
In [31]: m2 = so.Model(name='m2', session=session)
NOTE: Initialized model m2.
In [32]: table = session.upload_frame(df)
NOTE: Cloud Analytic Services made the uploaded file available as table TMP4I8FIETC in caslib CASUSER(casuser).
NOTE: The table TMP4I8FIETC has been created in caslib CASUSER(casuser) from binary data uploaded to Cloud Analytic Services.
In [33]: print(type(table), table)
<class 'swat.cas.table.CASTable'> CASTable('TMP4I8FIETC', caslib='CASUSER(casuser)')
In [34]: df = pd.DataFrame(data, columns=['item', 'value', 'weight', 'limit'])
In [35]: ITEMS = m.add_set(name='ITEMS')
In [36]: value = m.add_parameter(ITEMS, name='value')
In [37]: weight = m.add_parameter(ITEMS, name='weight')
In [38]: limit = m.add_parameter(ITEMS, name='limit')
In [39]: from sasoptpy.actions import read_data
In [40]: m.include(read_data(table=table, index={'target': ITEMS, 'key': None},
....: columns=[value, weight, limit]))
....:
In [41]: get3 = m2.add_variables(ITEMS, name='get3')
In [42]: print(get3)
Variable Group (get3) [
]
Abstract Data¶
If you would like to model your problem first and load data later, you can pass a string for the data that will be available later.
In [43]: from sasoptpy.actions import read_data
In [44]: m3 = so.Model(name='m3', session=session)
NOTE: Initialized model m3.
In [45]: ITEMS = m.add_set(name='ITEMS')
In [46]: limit = m.add_parameter(ITEMS, name='limit')
In [47]: m3.include(read_data(table='DF', index=['item'], columns=[limit]))
In [48]: print(type(ITEMS), ITEMS)
<class 'sasoptpy.abstract.set.Set'> ITEMS
Note that the key set is created as a reference. You can solve the
problem later after having the data available with the same name (for example, by using the
swat.cas.connection.CAS.upload_frame()
function)
In [49]: session.upload_frame(df, casout='DF')
NOTE: Cloud Analytic Services made the uploaded file available as table DF in caslib CASUSER(casuser).
NOTE: The table DF has been created in caslib CASUSER(casuser) from binary data uploaded to Cloud Analytic Services.
Out[49]: CASTable('DF', caslib='CASUSER(casuser)')
Operations¶
You can use lists, pandas.Series
, and pandas.DataFrame
objects for mathematical operations
such as VariableGroup.mult()
.
In [50]: sd = [3, 5, 6]
In [51]: z = m.add_variables(3, name='z')
In [52]: print(z)
Variable Group (z) [
[0: z[0]]
[1: z[1]]
[2: z[2]]
]
In [53]: print(repr(z))
sasoptpy.VariableGroup([0, 1, 2], name='z')
In [54]: e1 = z.mult(sd)
In [55]: print(e1)
3 * z[0] + 5 * z[1] + 6 * z[2]
In [56]: ps = pd.Series(sd)
In [57]: e2 = z.mult(ps)
In [58]: print(e2)
3 * z[0] + 5 * z[1] + 6 * z[2]