JijModeling 1.9.0 Release Note#
Random Generation for Instance Data#
jijmodeling
now supports random data generation for placeholders!It can be useful to distribute your model with dummy data and/or test the behaviour of models against small toy inputs.
For more details see the API documentations of
Problem.generate_random_dataset
andProblem.generate_random_instance
.
Problem.generate_random_dataset
and Problem.generate_random_instance
#
The function
Problem.generate_random_dataset
generates a dictionary of input values to be fed intojm.Interpreter
.Use
Problem.generate_random_instance
to directly generating OMMX instance without manually initiatingInterpreter
.
Overview#
To use random generation feature, you should specify some information in Placeholder
declaration.
The following random-generation related attributes are added in this version:
dtype
: The type of the element of an array (or scalar). Must be eitherjm.DataType.INTEGER
orjm.DataType.FLOAT
.jagged
: set toTrue
to generate a jagged array.False
by default.shape
: To generate an \(n\)-dimensional array or jagged array, you should specify the shape. This should be a tuple, with components dimension expression orNone
.None
means the size of the axis is indeterminate. For \(n\)-dimensional array, each axis has random but fixed size regardless of parent axes; for jagged arrays, the same axis can have different size for each parent axes.
If only dtype
is specified, the placeholder is considered as a scalar value as in other cases.
Problem.generate_random_*
takes the following keyword arguments:
seed
(optional): a seed for random data generation. If omitted, it samples from environmental entropy.options
(optional): ranges for values and axis size for each placeholder.default
(optional): default ranges option for placeholders absent inoptions
argument.
You will specify range objects in options
and default
. A concrete syntax is described in “Range Parameters and Range Syntax” section of API Reference.
In a nutshell, range object consists of the following fields:
value
: range of the values in placeholder. (default: uniformly samples from closed interval \([-1, 1]\))size
: range of the size of each axis in placeholder - ignored for scalar placeholders. (default: uniformly samples from closed interval \([1, 5] \cap \mathbb{N}\))
You can use functions from jijmodeling.range
, jijmodeling.range.value
, or jijmodeling.range.size
modules and builtin range(N, M)
function for size
range.
Examples#
import jijmodeling as jm
v = jm.Placeholder("v", dtype=jm.DataType.INTEGER, shape=[None])
N = v.len_at(0, latex="n")
w = jm.Placeholder("w", dtype=jm.DataType.FLOAT, shape=[N])
C = jm.Placeholder("C", dtype=jm.DataType.FLOAT)
x = jm.BinaryVar("x", shape=[N])
i = jm.Element("i", belong_to=N)
problem = jm.Problem("MyProblem", sense=jm.ProblemSense.MAXIMIZE)
problem += jm.sum(i, v[i] * x[i])
problem += jm.Constraint("capacity", jm.sum(i, w[i] * x[i]) <= C)
problem
# Get the dictionary of generated data
data_set = problem.generate_random_dataset(
seed=42,
# Default Options.
default={
"value": jm.range.open_closed(5, 15), # Samples values 5 < x <= 15
},
# Placheolder specific options.
options={
"v": {
"value": range(1000, 10000),
"size": range(2, 10), # Each axis should be of length 2 <= n < 10
}
},
)
data_set
{'C': 13.010242975288078,
'v': array([7120., 9322., 9926., 7927., 7473.]),
'w': array([13.50008444, 12.61374381, 10.8334931 , 11.8245287 , 7.90677762])}
config = {
"seed": 42,
# Default Options.
"default": {
"value": jm.range.open_closed(5, 15), # Samples values 5 < x <= 15
},
# Placheolder specific options.
"options": {
"v": {
"value": range(1000, 10000),
"size": range(2, 10), # Each axis should be of length 2 <= n < 10
}
},
}
# `generate_random_instance` is just a wrapper around generate_random_dataset and `Interpreter.eval_problem`.
instance = problem.generate_random_instance(**config)
assert instance == jm.Interpreter(data_set).eval_problem(problem)
# $n$-dimensionary array vs jagged array.
N = jm.Placeholder("N", dtype=jm.DataType.INTEGER)
# When `jagged` unspecified (or set to `False`), the generated data will be a $n$-dimensionary array.
ND = jm.Placeholder("ND", dtype=jm.DataType.FLOAT, shape=[N, None])
# When `jagged` is set to `True`, the generated data will be a jagged array.
JD = jm.Placeholder("JD", dtype=jm.DataType.FLOAT, shape=[N, None], jagged=True)
W = jm.BinaryVar("W", shape=[N])
# Both ND and JD has ndim 3, but `None` has different meaning.
# Create dummy problem
problem = jm.Problem("MyProblem2")
problem += jm.sum(i, ND[i, 0] * JD[i, 0] * W[i])
data_set = problem.generate_random_dataset(
seed=42, default={"size": range(2, 5)}, options={"N": {"value": range(2, 7)}}
)
data_set["ND"]
array([[ 0.43851716, 0.70001689, 0.52274876, 0.16669862],
[ 0.36490574, -0.41864448, 0.6020486 , -0.35717673],
[ 0.42229989, 0.75553446, 0.23352309, 0.70278017],
[ 0.41508094, 0.41565856, -0.81427987, -0.64195438],
[-0.12760731, 0.20402936, -0.37202221, -0.02161649],
[-0.20201642, 0.57824385, 0.27011351, -0.53733093]])
jd = data_set["JD"]
assert type(jd) is jm.JaggedArray
jd.dim
2
[[jd.get([i, j]) for j in range(jd.size_at([i]))] for i in range(jd.size_at([]))]
[[0.24546263509057664, 0.7263253599570634, 0.8895181708443229],
[0.4939994897028319,
0.5691758844274051,
-0.9103425154924141,
-0.0625037501158896],
[0.40134384632666964, 0.6071495573420034, 0.6363935389166486],
[-0.748701159594753,
0.1299655840672893,
0.1084981932704634,
0.7144708283472148],
[0.03940420021641855,
-0.3650379384649608,
-0.6156945696387756,
0.2877456030741061],
[-0.2834771222423055, 0.13862576961911643]]