.. include:: ../shared/configurators.rst .. _system-black-box: System Black Box ----------------------------------------------- The BlackBox modules provides utilities to run external scripts and programs in a constrained environment and parse the result. .. py:module:: optilog.blackbox :noindex: .. autoclass:: SystemBlackBox .. autoclass:: BlackBoxRedirection Here we have a basic example of a blackbox execution with parsing and memory limitations. Notice the usage of the placeholder `SystemBlackBox.Instance`. This will be replaced by the instance specified passed to `run`. .. code:: python :number-lines: from optilog.blackbox import SystemBlackBox, ExecutionConstraints, RunSolver from optilog.running import ParsingInfo parsing_info = ParsingInfo() parsing_info.add_filter('conflicts', 'Num conflicts: (\d+)', cast_to=int) executor = SystemBlackBox( ['./solver.sh', SystemBlackBox.Instance], constraints=ExecutionConstraints( # will inject call with runsolver found in PATH s_wall_time=100, s_real_memory='100M', enforcer=RunSolver() ), parsing_info=parsing_info ) executor.run('path/to/instance') # wraps: ./solver.sh path/to/instance print(executor.conflicts) # 34 print(executor.parsed) # {'conflicts': 34} Here we have a more complex example with configuration. To have a higher flexibility, we extend the `BlackBox` class. As ``./solver.sh`` expects the boolean parameters as flags, we override the ``format_config`` method to add the flag only when needed, instead of having `--flag=True` to the command call. Notice that we still have to add the *args* reveived by `format_config`. .. code:: python :number-lines: from optilog.blackbox import SystemBlackBox from optilog.running import ParsingInfo from optilog.tuning.basis import Int, Real, Bool parsing_info = ParsingInfo() parsing_info.add_filter('conflicts', 'Num conflicts: (\d+)', cast_to=int) parsing_info.add_filter('instance', 'Instance Path: (.+)') class ExampleSolverBB(SystemBlackBox): config = { 'incReduceDB': Int(0, 2147483647, default=300), 'R': Real(1.001, 4.999, default=1.4), 'C': Bool(default=False) } def __init__(self, *args, **kwargs): super().__init__(arguments=['./solver.sh', SystemBlackBox.Instance], *args, **kwargs) def format_config(self, args): config = self.configured.copy() c = config.pop('C', False) extra_args = [] if c: extra_args += ['--C'] return args + extra_args + [ f'--{k}={v}' for k, v in config.items() ] executor = ExampleSolverBB(parsing_info=parsing_info) executor.set('incReduceDB', 20) # Set the parameter --incReduceDB=20 executor.set('C', True) # Set the flag --C executor.run('path/to/instance') # wraps: ./solver.sh path/to/instance --C --incReduceDB=20 print(executor.conflicts) ... print(executor.parsed) ... print(executor.stdout) ...