1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
Jip J. Dekker f2a1c4e389 Squashed 'software/mza/' content from commit f970a59b17
git-subtree-dir: software/mza
git-subtree-split: f970a59b177c13ca3dd8aaef8cc6681d83b7e813
2021-07-11 16:34:30 +10:00

102 lines
2.9 KiB
Python

import contextlib
import json
import sys
from ctypes.util import find_library
import cffi
DEBUG = False
def debugprint(*args):
if DEBUG:
print(*args, file=sys.stderr, flush=True)
ffi = cffi.FFI()
ffi.cdef(
"""
struct _MZNInstance;
typedef struct _MZNInstance* MZNInstance;
void set_rnd_seed(int seed);
MZNInstance minizinc_instance_init(const char* mza_file, const char* data_file, const char* solver);
void minizinc_instance_destroy(MZNInstance);
void minizinc_add_call(MZNInstance, const char* call, ...);
void minizinc_set_solution(MZNInstance, int def, int sol);
void minizinc_output_dict(MZNInstance, bool);
void minizinc_print_hedge(MZNInstance);
void minizinc_set_limit(MZNInstance, int limit);
void minizinc_push_state(MZNInstance);
void minizinc_pop_state(MZNInstance);
const char* minizinc_solve(MZNInstance);
"""
)
# Set LD_LIBRARY_PATH (DYLD_LIBRARY_PATH on macOS) to the folder containing the mza library.
lib = ffi.dlopen("mza")
def set_rnd_seed(seed: int):
debugprint(f"set_rnd_seed({seed});")
lib.set_rnd_seed(seed)
class Instance:
def __init__(self, mza_file, data_file, solver):
debugprint(
f'MZNInstance inst = minizinc_instance_init("{mza_file}", "{data_file}", "{solver}");'
)
self._ptr = lib.minizinc_instance_init(
mza_file.encode(), data_file.encode(), solver.encode()
)
def __del__(self):
debugprint(f"minizinc_instance_destroy(inst);")
lib.minizinc_instance_destroy(self._ptr)
self._ptr = None
def output_dict(self, b: bool):
debugprint(f"minizinc_output_dict(inst, {int(b)});")
lib.minizinc_output_dict(self._ptr, b)
def set_incumbent(self, sol):
for k, v in sol.items():
debugprint(f"minizinc_set_solution(inst, {k}, {v});")
lib.minizinc_set_solution(self._ptr, int(k), v)
def set_limit(self, limit):
debugprint(f"minizinc_set_limit(inst, {limit});")
lib.minizinc_set_limit(self._ptr, limit)
def print(self):
debugprint(f"minizinc_print_hedge(inst);")
lib.minizinc_print_hedge(self._ptr)
@contextlib.contextmanager
def branch(self):
try:
debugprint(f"minizinc_push_state(inst);")
lib.minizinc_push_state(self._ptr)
yield self
finally:
debugprint(f"minizinc_pop_state(inst);")
lib.minizinc_pop_state(self._ptr)
def add_call(self, call: str, *args):
debugprint(
f"minizinc_add_call(inst, \"{call}\"{''.join([', '+ str(i) for i in args])});"
)
lib.minizinc_add_call(
self._ptr, call.encode(), *[ffi.cast("int", i) for i in args]
)
def solve(self):
debugprint(f"minizinc_solve(inst);")
res = ffi.string(lib.minizinc_solve(self._ptr))
tmp = json.loads(res)
return tmp["status"], tmp["solution"]