VOCS data structure¶
Variables, Objectives, Constraints, and other Settings (VOCS) helps define our optimization problems.
In [1]:
Copied!
from xopt.vocs import VOCS
from xopt.vocs import form_objective_data
import pandas as pd
import numpy as np
from xopt.vocs import VOCS
from xopt.vocs import form_objective_data
import pandas as pd
import numpy as np
In [2]:
Copied!
Y = """
variables:
a: [0, 1e3] # Note that 1e3 usually parses as a str with YAML.
b: [-1, 1]
objectives:
c: maximize
d: minimize
constraints:
e: ['Less_than', 2]
f: ['greater_than', 0]
constants:
g: 1234
"""
vocs = VOCS.from_yaml(Y)
vocs
Y = """
variables:
a: [0, 1e3] # Note that 1e3 usually parses as a str with YAML.
b: [-1, 1]
objectives:
c: maximize
d: minimize
constraints:
e: ['Less_than', 2]
f: ['greater_than', 0]
constants:
g: 1234
"""
vocs = VOCS.from_yaml(Y)
vocs
Out[2]:
VOCS(variables={'a': (0.0, 1000.0), 'b': (-1.0, 1.0)}, constraints={'e': ('LESS_THAN', 2.0), 'f': ('GREATER_THAN', 0.0)}, objectives={'c': 'MAXIMIZE', 'd': 'MINIMIZE'}, constants={'g': 1234}, observables=[])
In [3]:
Copied!
# as dict
dict(vocs)
# as dict
dict(vocs)
Out[3]:
{'variables': {'a': (0.0, 1000.0), 'b': (-1.0, 1.0)},
'constraints': {'e': ('LESS_THAN', 2.0), 'f': ('GREATER_THAN', 0.0)},
'objectives': {'c': 'MAXIMIZE', 'd': 'MINIMIZE'},
'constants': {'g': 1234},
'observables': []}
In [4]:
Copied!
# re-parse dict
vocs2 = VOCS.from_dict(dict(vocs))
# re-parse dict
vocs2 = VOCS.from_dict(dict(vocs))
In [5]:
Copied!
# Check that these are the same
vocs2 == vocs
# Check that these are the same
vocs2 == vocs
Out[5]:
True
In [6]:
Copied!
# This replaces the old vocs["variables"]
getattr(vocs, "variables")
# This replaces the old vocs["variables"]
getattr(vocs, "variables")
Out[6]:
{'a': (0.0, 1000.0), 'b': (-1.0, 1.0)}
In [7]:
Copied!
vocs.objectives["c"] == "MAXIMIZE"
vocs.objectives["c"] == "MAXIMIZE"
Out[7]:
True
In [8]:
Copied!
# json
vocs.to_json()
# json
vocs.to_json()
Out[8]:
'{"variables":{"a":[0.0,1000.0],"b":[-1.0,1.0]},"constraints":{"e":["LESS_THAN",2.0],"f":["GREATER_THAN",0.0]},"objectives":{"c":"MAXIMIZE","d":"MINIMIZE"},"constants":{"g":1234},"observables":[]}'
Objective Evaluation¶
In [9]:
Copied!
data = pd.DataFrame(vocs.random_inputs(10))
# Add some outputs
data["c"] = data["a"] + data["b"]
data["d"] = data["a"] - data["b"]
data["e"] = data["a"] * 2 + data["b"] * 2
data["f"] = data["a"] * 2 - data["b"] * 2
data.index = np.arange(len(data)) + 5 # custom index
data
data = pd.DataFrame(vocs.random_inputs(10))
# Add some outputs
data["c"] = data["a"] + data["b"]
data["d"] = data["a"] - data["b"]
data["e"] = data["a"] * 2 + data["b"] * 2
data["f"] = data["a"] * 2 - data["b"] * 2
data.index = np.arange(len(data)) + 5 # custom index
data
Out[9]:
| a | b | g | c | d | e | f | |
|---|---|---|---|---|---|---|---|
| 5 | 927.031624 | 0.645742 | 1234 | 927.677366 | 926.385882 | 1855.354731 | 1852.771765 |
| 6 | 773.282104 | -0.163225 | 1234 | 773.118879 | 773.445329 | 1546.237758 | 1546.890659 |
| 7 | 920.579358 | 0.717932 | 1234 | 921.297289 | 919.861426 | 1842.594579 | 1839.722852 |
| 8 | 268.308512 | 0.234685 | 1234 | 268.543197 | 268.073827 | 537.086395 | 536.147654 |
| 9 | 122.172565 | 0.595717 | 1234 | 122.768282 | 121.576849 | 245.536564 | 243.153697 |
| 10 | 381.696110 | 0.794627 | 1234 | 382.490738 | 380.901483 | 764.981475 | 761.802965 |
| 11 | 366.802322 | -0.406137 | 1234 | 366.396184 | 367.208459 | 732.792368 | 734.416918 |
| 12 | 142.342224 | -0.943329 | 1234 | 141.398895 | 143.285554 | 282.797790 | 286.571108 |
| 13 | 807.685927 | -0.150885 | 1234 | 807.535042 | 807.836812 | 1615.070085 | 1615.673625 |
| 14 | 646.629452 | -0.145523 | 1234 | 646.483929 | 646.774975 | 1292.967857 | 1293.549949 |
In [10]:
Copied!
vocs.objectives
vocs.objectives
Out[10]:
{'c': 'MAXIMIZE', 'd': 'MINIMIZE'}
In [11]:
Copied!
# These are in standard form for minimization
form_objective_data(vocs.objectives, data)
# These are in standard form for minimization
form_objective_data(vocs.objectives, data)
Out[11]:
| objective_c | objective_d | |
|---|---|---|
| 5 | -927.677366 | 926.385882 |
| 6 | -773.118879 | 773.445329 |
| 7 | -921.297289 | 919.861426 |
| 8 | -268.543197 | 268.073827 |
| 9 | -122.768282 | 121.576849 |
| 10 | -382.490738 | 380.901483 |
| 11 | -366.396184 | 367.208459 |
| 12 | -141.398895 | 143.285554 |
| 13 | -807.535042 | 807.836812 |
| 14 | -646.483929 | 646.774975 |
In [12]:
Copied!
# This is also available as a method
vocs.objective_data(data)
# This is also available as a method
vocs.objective_data(data)
Out[12]:
| objective_c | objective_d | |
|---|---|---|
| 5 | -927.677366 | 926.385882 |
| 6 | -773.118879 | 773.445329 |
| 7 | -921.297289 | 919.861426 |
| 8 | -268.543197 | 268.073827 |
| 9 | -122.768282 | 121.576849 |
| 10 | -382.490738 | 380.901483 |
| 11 | -366.396184 | 367.208459 |
| 12 | -141.398895 | 143.285554 |
| 13 | -807.535042 | 807.836812 |
| 14 | -646.483929 | 646.774975 |
In [13]:
Copied!
# use the to_numpy() method to convert for low level use.
vocs.objective_data(data).to_numpy()
# use the to_numpy() method to convert for low level use.
vocs.objective_data(data).to_numpy()
Out[13]:
array([[-927.67736571, 926.38588235],
[-773.11887905, 773.44532948],
[-921.29728941, 919.86142599],
[-268.54319738, 268.07382697],
[-122.76828176, 121.57684861],
[-382.49073755, 380.90148266],
[-366.3961842 , 367.20845905],
[-141.39889479, 143.28555375],
[-807.53504241, 807.83681234],
[-646.48392857, 646.77497452]])
In [14]:
Copied!
vocs.constraint_data(data)
vocs.constraint_data(data)
Out[14]:
| constraint_e | constraint_f | |
|---|---|---|
| 5 | 1853.354731 | -1852.771765 |
| 6 | 1544.237758 | -1546.890659 |
| 7 | 1840.594579 | -1839.722852 |
| 8 | 535.086395 | -536.147654 |
| 9 | 243.536564 | -243.153697 |
| 10 | 762.981475 | -761.802965 |
| 11 | 730.792368 | -734.416918 |
| 12 | 280.797790 | -286.571108 |
| 13 | 1613.070085 | -1615.673625 |
| 14 | 1290.967857 | -1293.549949 |
In [15]:
Copied!
vocs.feasibility_data(data)
vocs.feasibility_data(data)
Out[15]:
| feasible_e | feasible_f | feasible | |
|---|---|---|---|
| 5 | False | True | False |
| 6 | False | True | False |
| 7 | False | True | False |
| 8 | False | True | False |
| 9 | False | True | False |
| 10 | False | True | False |
| 11 | False | True | False |
| 12 | False | True | False |
| 13 | False | True | False |
| 14 | False | True | False |
In [16]:
Copied!
# normalize inputs to unit domain [0,1]
normed_data = vocs.normalize_inputs(data)
normed_data
# normalize inputs to unit domain [0,1]
normed_data = vocs.normalize_inputs(data)
normed_data
Out[16]:
| a | b | |
|---|---|---|
| 5 | 0.927032 | 0.822871 |
| 6 | 0.773282 | 0.418387 |
| 7 | 0.920579 | 0.858966 |
| 8 | 0.268309 | 0.617343 |
| 9 | 0.122173 | 0.797858 |
| 10 | 0.381696 | 0.897314 |
| 11 | 0.366802 | 0.296931 |
| 12 | 0.142342 | 0.028335 |
| 13 | 0.807686 | 0.424558 |
| 14 | 0.646629 | 0.427239 |
In [17]:
Copied!
# and denormalize
vocs.denormalize_inputs(normed_data)
# and denormalize
vocs.denormalize_inputs(normed_data)
Out[17]:
| a | b | |
|---|---|---|
| 5 | 927.031624 | 0.645742 |
| 6 | 773.282104 | -0.163225 |
| 7 | 920.579358 | 0.717932 |
| 8 | 268.308512 | 0.234685 |
| 9 | 122.172565 | 0.595717 |
| 10 | 381.696110 | 0.794627 |
| 11 | 366.802322 | -0.406137 |
| 12 | 142.342224 | -0.943329 |
| 13 | 807.685927 | -0.150885 |
| 14 | 646.629452 | -0.145523 |
Error handling¶
In [18]:
Copied!
Y = """
variables:
a: [0, 1e3] # Note that 1e3 usually parses as a str with YAML.
b: [-1, 1]
objectives:
c: maximize
d: minimize
constraints:
e: ['Less_than', 2]
f: ['greater_than', 0]
constants:
g: 1234
"""
vocs = VOCS.from_yaml(Y)
Y = """
variables:
a: [0, 1e3] # Note that 1e3 usually parses as a str with YAML.
b: [-1, 1]
objectives:
c: maximize
d: minimize
constraints:
e: ['Less_than', 2]
f: ['greater_than', 0]
constants:
g: 1234
"""
vocs = VOCS.from_yaml(Y)
In [19]:
Copied!
d = {"a": [1, 2, 3]}
df = pd.DataFrame(d)
df2 = pd.DataFrame(df).copy()
df2["b"] = np.nan
df2["b"] - 1
d = {"a": [1, 2, 3]}
df = pd.DataFrame(d)
df2 = pd.DataFrame(df).copy()
df2["b"] = np.nan
df2["b"] - 1
Out[19]:
0 NaN 1 NaN 2 NaN Name: b, dtype: float64
In [20]:
Copied!
data["a"] = np.nan
data["a"] = np.nan
In [21]:
Copied!
a = 2
def f(x=a):
return x
a = 99
f()
a = 2
def f(x=a):
return x
a = 99
f()
Out[21]:
2
In [22]:
Copied!
pd.DataFrame(6e66, index=[1, 2, 3], columns=["A"])
pd.DataFrame(6e66, index=[1, 2, 3], columns=["A"])
Out[22]:
| A | |
|---|---|
| 1 | 6.000000e+66 |
| 2 | 6.000000e+66 |
| 3 | 6.000000e+66 |
In [23]:
Copied!
# These are in standard form for minimization
data = pd.DataFrame({"c": [1, 2, 3, 4]}, index=[9, 3, 4, 5])
form_objective_data(vocs.objectives, data)
# These are in standard form for minimization
data = pd.DataFrame({"c": [1, 2, 3, 4]}, index=[9, 3, 4, 5])
form_objective_data(vocs.objectives, data)
Out[23]:
| objective_c | objective_d | |
|---|---|---|
| 9 | -1.0 | inf |
| 3 | -2.0 | inf |
| 4 | -3.0 | inf |
| 5 | -4.0 | inf |