JijModeling 2.12.0 Release Notes#

Feature Enhancements#

Streams and dictionaries as placeholder dtype#

You can now define placeholders with composite types (placeholders whose containers can be nested as needed by combining jm.DataType.STREAM, jm.DataType.PARTIAL_DICT, and jm.DataType.TOTAL_DICT in dtype and using settings such as ndim=).

The following example defines an array x of N binary decision variables and a one-dimensional placeholder A whose elements are streams of pairs consisting of a coefficient c and an index i into x.

import jijmodeling as jm

@jm.Problem.define("problem")
def problem(problem: jm.DecoratedProblem):
    N = problem.Natural("N")
    x = problem.BinaryVar("x", shape=N)
    A = problem.Placeholder("A", dtype=jm.DataType.STREAM[(float, N)], ndim=1)
    problem += problem.Constraint(
        "weighted-sum", [jm.sum(c * x[i] for c, i in terms) <= 1 for terms in A]
    )

The streams do not need to have the same length, so the model can accept instance data such as the following:

problem.eval({
    "N": 3,
    "A": [
        [(0.5, 0), (0.75, 1)],
        [(1.0, 2)],
    ],
})
Instance(raw=<builtins.Instance object at 0x75305bf900>, annotations={})

The elements of this A correspond to the following constraints, respectively:

\[ \begin{aligned} 0.5 x_0 + 0.75 x_1 &\le 1, \\ x_2 &\le 1. \end{aligned} \]

Tip

Placeholders with composite types allow you to define data types whose rows can have different lengths.

Earlier versions of JijModeling required Jagged Arrays for this kind of formulation. However, while Jagged Arrays allow random access to their elements, they offer limited benefits from type checking and are deprecated in JijModeling 2.

We therefore encourage you to use placeholders with composite types for this kind of formulation.

Bugfixes#

Bugfix: Fix compilation of constraints with a stream of tuples as its domain#

Fixed an issue where using a stream of tuples, such as dictionary placeholder’s keys(), as a constraint’s domain parameter would raise type error E-TE0014.

import jijmodeling as jm

@jm.Problem.define("problem")
def problem(problem: jm.DecoratedProblem):
    N = problem.Length()
    c = problem.PartialDict(dtype=float, dict_keys=(N, N))
    x = problem.BinaryVar(dict_keys=c.keys())
    problem += problem.Constraint("fixed", [x[i, j] == 1 for i, j in c.keys()])

problem.eval({"N": 2, "c": {(0, 0): 1.0, (1, 1): 1.0}})
Instance(raw=<builtins.Instance object at 0x7531fdf900>, annotations={})

Bugfix: Fix infinite loops in constraint detection caused by floating-point rounding errors#

Fixed a bug that could cause constraint detection to loop indefinitely when variable bounds or subexpressions in the objective function or constraints contained values that could not be handled exactly in floating-point arithmetic. This did not occur when constants were modeled as placeholders and floating-point values were supplied as instance data. However, specifying floating-point values directly in the model, as in the following example, could cause an infinite loop.

import jijmodeling as jm


problem = jm.Problem("decimal bounds")

problem.ContinuousVar("ratio", lower_bound=0.1, upper_bound=0.5)
instance = problem.eval({})

Starting with this release, constant folding is performed only when the arithmetic is exact, preventing this issue. As a result, some transcendental functions now appear without simplification in \(\LaTeX\) output.