Skip to content

Commit

Permalink
Stop checking minzinc binary at discrete_optimization import
Browse files Browse the repository at this point in the history
Instead, we raise the same error (with explicit message) only when
initializing a minizinc-based solver, thanks to the method
find_right_minizinc_solver_name() used by each solver.

We transform the relevant test in github workflow accordingly, and
update the docs.

We also upgrade the minimal requirement to 2.8.
  • Loading branch information
nhuet authored and g-poveda committed Oct 1, 2024
1 parent 4b68374 commit 625fb4f
Show file tree
Hide file tree
Showing 16 changed files with 39 additions and 113 deletions.
13 changes: 5 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,19 +163,16 @@ jobs:
python -m pip install -U pip
wheelfile=$(ls ./dist/discrete_optimization*.whl)
pip install ${wheelfile}
- name: Check import work without minizinc if DO_SKIP_MZN_CHECK set
run: |
export DO_SKIP_MZN_CHECK=1
python -c "import discrete_optimization"
- name: Check import fails without minizinc if DO_SKIP_MZN_CHECK unset
- name: Check minizinc based solvers fails without minizinc binary
run: |
python -c "
try:
import discrete_optimization
from discrete_optimization.generic_tools.cp_tools import find_right_minizinc_solver_name, CPSolverName
find_right_minizinc_solver_name(CPSolverName.CHUFFED)
except RuntimeError:
pass
else:
raise AssertionError('We should not be able to import discrete_optimization without minizinc being installed.')
raise AssertionError('We should not be able to `find_right_minizinc_solver_name()` without minizinc being installed.')
"
- name: Create bin/
run: mkdir -p bin
Expand Down Expand Up @@ -208,7 +205,7 @@ jobs:
run: |
# configure minizinc
${{ matrix.minizinc_config_cmdline }}
# check imports
# check imports
python tests/test_import_all_submodules.py
- name: Install test dependencies
run: |
Expand Down
28 changes: 0 additions & 28 deletions discrete_optimization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,10 @@
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import os
from importlib.metadata import PackageNotFoundError, version

try:
__version__ = version("discrete-optimization")
except PackageNotFoundError:
# package is not installed
pass

# Check that minimal minizinc binary version is respected,
# except if environment variable DO_SKIP_MZN_CHECK is set to 1.
if ("DO_SKIP_MZN_CHECK" not in os.environ) or not (os.environ["DO_SKIP_MZN_CHECK"]):
import minizinc

_minizinc_minimal_parsed_version = (2, 6)
_minizinc_minimal_str_version = ".".join(
str(i) for i in _minizinc_minimal_parsed_version
)

if minizinc.default_driver is None:
raise RuntimeError(
"Minizinc binary has not been found.\n"
"You need to install it and/or configure the PATH environment variable.\n"
"See minizinc documentation for more details: https://www.minizinc.org/doc-latest/en/installation.html\n\n"
"You can also bypass this check by setting the environment variable DO_SKIP_MZN_CHECK to 1, "
"at your own risk."
)
if minizinc.default_driver.parsed_version < _minizinc_minimal_parsed_version:
raise RuntimeError(
f"Minizinc binary version must be at least {_minizinc_minimal_str_version}.\n"
"Install an appropriate version of minizinc and/or configure the PATH environment variable.\n"
"See minizinc documentation for more details: https://www.minizinc.org/doc-latest/en/installation.html\n\n"
"You can also bypass this check by setting the environment variable DO_SKIP_MZN_CHECK to 1, "
"at your own risk."
)
22 changes: 21 additions & 1 deletion discrete_optimization/generic_tools/cp_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,34 @@ class CPSolverName(Enum):
}


_minizinc_minimal_parsed_version = (2, 8)
_minizinc_minimal_str_version = ".".join(
str(i) for i in _minizinc_minimal_parsed_version
)


def find_right_minizinc_solver_name(cp_solver_name: CPSolverName):
"""
This small utility function is adapting the ortools tag if needed.
:param cp_solver_name: desired cp solver backend
:return: the tag for minizinc corresponding to the given cpsolver.
"""
driver = minizinc.default_driver
assert driver is not None

# Check minzinc binary is found and has proper version
if minizinc.default_driver is None:
raise RuntimeError(
"Minizinc binary has not been found.\n"
"You need to install it and/or configure the PATH environment variable.\n"
"See minizinc documentation for more details: https://www.minizinc.org/doc-latest/en/installation.html."
)
if minizinc.default_driver.parsed_version < _minizinc_minimal_parsed_version:
raise RuntimeError(
f"Minizinc binary version must be at least {_minizinc_minimal_str_version}.\n"
"Install an appropriate version of minizinc and/or configure the PATH environment variable.\n"
"See minizinc documentation for more details: https://www.minizinc.org/doc-latest/en/installation.html."
)

tag_map = driver.available_solvers(False)
if map_cp_solver_name[cp_solver_name] not in tag_map:
if cp_solver_name == CPSolverName.ORTOOLS:
Expand Down
2 changes: 0 additions & 2 deletions discrete_optimization/maximum_independent_set/mis_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from discrete_optimization.generic_tools.graph_api import Graph
from discrete_optimization.maximum_independent_set.mis_model import MisProblem

os.environ["DO_SKIP_MZN_CHECK"] = "1"


def get_data_available(
data_folder: Optional[str] = None, data_home: Optional[str] = None
Expand Down
26 changes: 7 additions & 19 deletions docs/source/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

## Prerequisites

### Minizinc 2.6+
### Minizinc 2.8+

You need to install [minizinc](https://www.minizinc.org/) (version greater than 2.6) and update the `PATH` environment variable
If you want to use discrete-optimization solvers based on [minizinc](https://www.minizinc.org/),
you need to install it (version greater than 2.8) and update the `PATH` environment variable
so that it can be found by Python.
See [minizinc documentation](https://www.minizinc.org/doc-latest/en/installation.html) for more details.

Expand All @@ -19,7 +20,7 @@ On a Linux distribution, you can use the bundled [minizinc AppImage](https://www
If [FUSE](https://en.wikipedia.org/wiki/Filesystem_in_Userspace) is available:
```
mkdir minizinc_install
curl -o minizinc_install/minizinc -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.6.3/MiniZincIDE-2.6.3-x86_64.AppImage
curl -o minizinc_install/minizinc -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.8.5/MiniZincIDE-2.8.5-x86_64.AppImage
chmod +x minizinc_install/minizinc
export PATH="$(pwd)/minizinc_install/":$PATH
minizinc --version
Expand All @@ -28,7 +29,7 @@ Else, this is still possible by extracting the files:
```
mkdir minizinc_install
cd minizinc_install
curl -o minizinc.AppImage -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.6.3/MiniZincIDE-2.6.3-x86_64.AppImage
curl -o minizinc.AppImage -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.8.5/MiniZincIDE-2.8.5-x86_64.AppImage
chmod +x minizinc.AppImage
./minizinc.AppImage --appimage-extract
cd ..
Expand All @@ -40,7 +41,7 @@ minizinc --version
#### MacOs command line
```
mkdir minizinc_install
curl -o minizinc.dmg -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.6.3/MiniZincIDE-2.6.3-bundled.dmg
curl -o minizinc.dmg -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.8.5/MiniZincIDE-2.8.5-bundled.dmg
hdiutil attach minizinc.dmg
cp -R /Volumes/MiniZinc*/MiniZincIDE.app minizinc_install/.
export PATH="$(pwd)/minizinc_install/MiniZincIDE.app/Contents/Resources":$PATH
Expand All @@ -51,25 +52,12 @@ minizinc --version
Works on Windows Server 2022 with bash shell:
```
mkdir minizinc_install
curl -o minizinc_setup.exe -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.6.3/MiniZincIDE-2.6.3-bundled-setup-win64.exe
curl -o minizinc_setup.exe -L https://github.com/MiniZinc/MiniZincIDE/releases/download/2.8.5/MiniZincIDE-2.8.5-bundled-setup-win64.exe
cmd //c "minizinc_setup.exe /verysilent /currentuser /norestart /suppressmsgboxes /sp"
export PATH="~/AppData/Local/Programs/MiniZinc":$PATH
minizinc --version
```

#### Skipping minizinc version check

It may happen that you need to use only a part of the library which is not relying on minizinc at all,
and that you do not want to install minzinc.
This can be troublesome as the minizinc binary version is checked at library import.
We provide a way to bypass this check by setting the environment variable DO_SKIP_MZN_CHECK:
```shell
export DO_SKIP_MZN_CHECK=1
```
Please note however that the library is never tested without minizinc (or minizinc versions < 2.6).
Most modules related to solvers will fail to be imported without minizinc as they are heavily relying on it.


### Python 3.7+ environment

The use of a virtual environment is recommended, and you will need to ensure that the environment use a Python version
Expand Down
4 changes: 0 additions & 4 deletions examples/coloring/coloring_asp_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@
# LICENSE file in the root directory of this source tree.

import logging
import os

from discrete_optimization.coloring.coloring_model import (
ConstraintsColoring,
transform_coloring_problem,
)

os.environ["DO_SKIP_MZN_CHECK"] = "1"

from discrete_optimization.coloring.coloring_parser import (
get_data_available,
parse_file,
Expand Down
7 changes: 1 addition & 6 deletions examples/coloring/coloring_cpspat_solver_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.


import logging
import os

from discrete_optimization.coloring.coloring_model import (
ConstraintsColoring,
transform_coloring_problem,
)

os.environ["DO_SKIP_MZN_CHECK"] = "1"

import logging

from discrete_optimization.coloring.coloring_parser import (
get_data_available,
parse_file,
Expand Down
4 changes: 0 additions & 4 deletions examples/coloring/toulbar_coloring_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
# LICENSE file in the root directory of this source tree.

import logging
import os

os.environ["DO_SKIP_MZN_CHECK"] = "1"
from discrete_optimization.coloring.coloring_model import (
ColoringProblem,
ColoringSolution,
ConstraintsColoring,
transform_coloring_problem,
)
Expand Down
2 changes: 0 additions & 2 deletions examples/knapsack/knapsack_asp_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
# LICENSE file in the root directory of this source tree.

import logging
import os

os.environ["DO_SKIP_MZN_CHECK"] = "1"
from discrete_optimization.knapsack.knapsack_parser import (
get_data_available,
parse_file,
Expand Down
4 changes: 0 additions & 4 deletions examples/knapsack/knapsack_decomposition_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
# LICENSE file in the root directory of this source tree.

import logging
import os

from discrete_optimization.generic_tools.hyperparameters.hyperparameter import SubBrick

os.environ["DO_SKIP_MZN_CHECK"] = "1"
from discrete_optimization.generic_tools.cp_tools import ParametersCP
from discrete_optimization.knapsack.knapsack_parser import (
get_data_available,
parse_file,
Expand Down
18 changes: 5 additions & 13 deletions examples/maximum_independent_set/optuna_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,22 @@
"""

import os

from discrete_optimization.maximum_independent_set.solvers.mis_kamis import (
MisKamisSolver,
)

os.environ["DO_SKIP_MZN_CHECK"] = "1"

import logging
import os
import time
from collections import defaultdict
from typing import Any

import optuna
from optuna import Trial
from optuna.storages import JournalFileStorage, JournalStorage
from optuna.trial import TrialState

from discrete_optimization.generic_tools.callbacks.loggers import ObjectiveLogger
from discrete_optimization.generic_tools.callbacks.optuna import OptunaCallback
from discrete_optimization.generic_tools.cp_tools import ParametersCP
from discrete_optimization.generic_tools.do_problem import ModeOptim
from discrete_optimization.generic_tools.do_solver import SolverDO
from discrete_optimization.generic_tools.lp_tools import (
ParametersMilp,
gurobi_available,
)
from discrete_optimization.generic_tools.lp_tools import gurobi_available
from discrete_optimization.generic_tools.optuna.timed_percentile_pruner import (
TimedPercentilePruner,
)
Expand All @@ -48,6 +37,9 @@
MisMilpSolver,
MisQuadraticSolver,
)
from discrete_optimization.maximum_independent_set.solvers.mis_kamis import (
MisKamisSolver,
)
from discrete_optimization.maximum_independent_set.solvers.mis_networkx import (
MisNetworkXSolver,
)
Expand Down
4 changes: 0 additions & 4 deletions examples/qiskit_examples/qiskit_optuna_coloring.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@
"""

import os

os.environ["DO_SKIP_MZN_CHECK"] = "1"

import logging
import time
from typing import Any

import optuna
from optuna import Trial
from optuna.storages import JournalFileStorage, JournalStorage
from optuna.trial import TrialState

from discrete_optimization.coloring.coloring_model import ColoringProblem
Expand Down
4 changes: 0 additions & 4 deletions examples/qiskit_examples/qiskit_optuna_knapsack.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@
"""

import os

os.environ["DO_SKIP_MZN_CHECK"] = "1"

import logging
import time
from typing import Any

import optuna
from optuna import Trial
from optuna.storages import JournalFileStorage, JournalStorage
from optuna.trial import TrialState

from discrete_optimization.generic_tools.callbacks.loggers import ObjectiveLogger
Expand Down
4 changes: 0 additions & 4 deletions examples/qiskit_examples/qiskit_optuna_mis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
"""

import os

os.environ["DO_SKIP_MZN_CHECK"] = "1"

import logging
import time
Expand All @@ -20,7 +17,6 @@
import networkx as nx
import optuna
from optuna import Trial
from optuna.storages import JournalFileStorage, JournalStorage
from optuna.trial import TrialState

from discrete_optimization.generic_tools.callbacks.loggers import ObjectiveLogger
Expand Down
5 changes: 0 additions & 5 deletions examples/qiskit_examples/qiskit_optuna_tsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,12 @@
"""

import os

os.environ["DO_SKIP_MZN_CHECK"] = "1"

import logging
import time
from typing import Any

import optuna
from optuna import Trial
from optuna.storages import JournalFileStorage, JournalStorage
from optuna.trial import TrialState

from discrete_optimization.generic_tools.callbacks.loggers import ObjectiveLogger
Expand Down
5 changes: 0 additions & 5 deletions examples/rcpsp/rcpsp_lp_cplex_solver.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
# Copyright (c) 2023 AIRBUS and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
import os

from discrete_optimization.datasets import get_data_home

os.environ["DO_SKIP_MZN_CHECK"] = "1"
from discrete_optimization.generic_tools.lp_tools import ParametersMilp
from discrete_optimization.generic_tools.result_storage.result_storage import (
ResultStorage,
)
from discrete_optimization.rcpsp.rcpsp_model import RCPSPModel
from discrete_optimization.rcpsp.rcpsp_parser import get_data_available, parse_file
from discrete_optimization.rcpsp.rcpsp_solution import RCPSPSolution
from discrete_optimization.rcpsp.rcpsp_utils import (
plot_resource_individual_gantt,
plot_ressource_view,
Expand Down

0 comments on commit 625fb4f

Please sign in to comment.